首页 新闻 会员 周边

Blazor Service模式Excel导出没有进度?

0
悬赏园豆:10 [已解决问题] 解决于 2023-05-15 12:04

如题

按官方文档实现,下载过程无进度,不知道园子里有没有大神知道怎么解决这个问题。
https://learn.microsoft.com/zh-cn/aspnet/core/blazor/file-downloads?view=aspnetcore-7.0

我知道用原生的asp.net core api/mvc都可以实现,但不想在Blazor Service项目中嵌入api/mvc/Razor Pages

Adming的主页 Adming | 初学一级 | 园豆:119
提问于:2023-03-28 21:23
< >
分享
最佳答案
0

Blazor Service模式下的文件下载没有进度的问题可以通过以下方式解决:

  1. 使用HttpClient的Progress属性
    在Blazor Service项目中,可以使用HttpClient的Progress属性来获取下载进度信息。具体实现步骤如下:
  • 在调用服务端方法时,将HttpClient对象作为参数传递给服务端方法;
  • 在服务端方法中,使用HttpClient的GetAsync方法获取文件流,并根据文件大小来设置HttpContent的长度;
  • 在客户端代码中,使用HttpClient的GetStreamAsync方法获取文件流,并将其保存到本地文件或者在浏览器中打开;
  • 在客户端代码中,使用HttpClient的Progress属性来获取下载进度信息,并在页面上展示。
  1. 使用SignalR实时通信
    在Blazor Service项目中,可以使用SignalR实现服务端与客户端之间的实时通信,向客户端发送下载进度的消息。具体实现步骤如下:
  • 在服务端代码中,使用SignalR的Hub来实现文件下载功能,并在下载过程中向客户端发送下载进度的消息;
  • 在客户端代码中,使用SignalR的JavaScriptInterop来调用服务端方法,并在页面上展示下载进度。
    以上两种方式都可以解决Blazor Service模式下文件下载没有进度的问题,具体实现方式可以根据实际情况选择。
收获园豆:5
LuoCore | 初学一级 |园豆:122 | 2023-03-31 08:08

以下是使用HttpClient的Progress属性实现文件下载进度的示例代码:
在服务端代码中,定义一个下载文件的方法,该方法将HttpClient对象作为参数传递给服务端方法:

using System.Net.Http;
using System.IO;
using System.Threading.Tasks;
public async Task DownloadFile(HttpClient httpClient)
{
    var response = await httpClient.GetAsync("http://example.com/file.pdf", HttpCompletionOption.ResponseHeadersRead);
    response.EnsureSuccessStatusCode();
    var contentLength = response.Content.Headers.ContentLength;
    var stream = await response.Content.ReadAsStreamAsync();
    using var fileStream = new FileStream("file.pdf", FileMode.Create, FileAccess.Write, FileShare.None, 4096, true);
    byte[] buffer = new byte[8192];
    var totalRead = 0L;
    int read;
    while ((read = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
    {
        await fileStream.WriteAsync(buffer, 0, read);
        totalRead += read;
        var progress = (double)totalRead / contentLength;
        // 将下载进度发送给客户端
    }
}

在客户端代码中,调用服务端方法,并使用HttpClient的Progress属性来获取下载进度信息:

@using System.Net.Http
<button @onclick="DownloadFile">Download File</button>
@code {
    private readonly HttpClient _httpClient = new HttpClient();
    private async Task DownloadFile()
    {
        await MyService.DownloadFile(_httpClient);
    }
    private void OnProgress(HttpContentProgressEventArgs args)
    {
        // 更新下载进度
    }
    private void OnCompleted(HttpResponseMessage response)
    {
        // 下载完成
    }
}

在Blazor组件中注入服务端方法:

@using Microsoft.AspNetCore.Components
@inject MyService MyService

以上示例代码中,需要将下载进度发送给客户端,可以使用SignalR或者Blazor的JavaScriptInterop来实现。

LuoCore | 园豆:122 (初学一级) | 2023-03-31 08:09

@LuoCore: 谢谢,不过好像不对。
你这个DownloadFile 方法是在服务端运行的吧?那 var fileStream = new FileStream("file.pdf", FileMode.Create, FileAccess.Write, FileShare.None, 4096, true); 就是在服务端创建保存文件吧?
文件下载的目的是把服务器上的文件(磁盘上的静态文件和实时生成的虚拟文件流/字节)保存到客户端本地电脑磁盘。
其实服务器上有静态文件还好办,后端配置app.UseStaticFiles 或直接放置到wwwroot目录,用js直接打开文件路径(url)浏览器就能自动下载了,下载时有进度。
而且官方文件也有相应的解决方案(第二种方案,URL下载)。
https://learn.microsoft.com/zh-cn/aspnet/core/blazor/file-downloads?view=aspnetcore-7.0

现在的问题是,服务器上没有落盘,无具体实体文件(文件存储在对象存储、数据库或即时生成)。
因为没有实体文件,所以就没有供客户端访问的地址。
上面的官方文件第一种方案就是这种,但它是直接将二进制流转成JS,通过Blob、URL.createObjectURL()在客户端机器上生成虚拟URL来下载,可以下载,但下载过程无进度。

Adming | 园豆:119 (初学一级) | 2023-03-31 09:00

已经解决了,问题的关键在于不落盘的文件没有供客户端访问的URL地址,那么我们可以给它生成一个地址,用asp.net core api/mvc/razor page都可以实现,但这些太重了点。所有最后采用中件间来完成文件下载。
这样就可以摆脱Blazor Service单页面的限制,通过传统方法(URL)下载了。

Adming | 园豆:119 (初学一级) | 2023-03-31 09:09
其他回答(2)
0

Blazor Server模式是基于SignalR实现的,可以使用SignalR实时更新下载进度。但是Blazor WebAssembly模式是在客户端运行的,无法直接与服务器交互以获取下载进度。

为了解决这个问题,你可以通过在客户端实现一个进度条来模拟下载进度。这个进度条可以显示下载进度的百分比,并随着时间的推移逐渐增加。

你可以尝试使用JavaScript的XMLHttpRequest对象来实现进度条。XMLHttpRequest对象可以用于向服务器发送异步请求,并在请求过程中报告进度。在请求期间,XMLHttpRequest对象将触发progress事件,该事件将提供有关请求进度的信息,例如下载的字节数和总字节数。

以下是一个示例,演示如何使用XMLHttpRequest对象在Blazor WebAssembly应用程序中实现下载进度:

在你的Blazor WebAssembly项目中创建一个名为DownloadService的服务类。

在DownloadService类中添加一个DownloadFileAsync方法,用于下载文件。这个方法应该返回一个Task<byte[]>对象,表示下载的文件内容。

在DownloadFileAsync方法中,使用XMLHttpRequest对象从服务器下载文件,并在下载过程中报告进度。

在Blazor WebAssembly应用程序中创建一个DownloadButton组件,并将DownloadService注入到该组件中。

当用户单击DownloadButton时,调用DownloadService的DownloadFileAsync方法,获取下载的文件内容,并使用JavaScript代码将下载进度显示在进度条中。

收获园豆:5
Technologyforgood | 园豆:6170 (大侠五级) | 2023-03-28 21:34

有点晕,用 XMLHttpRequest 和前后端分离项目中在前端用JS调用api/mvc URL地址下载差不多吧?
但是如何在 Blazor 中用JS、XMLHttpRequest 调用 DownloadService的DownloadFileAsync

支持(0) 反对(0) Adming | 园豆:119 (初学一级) | 2023-03-28 21:53

@Adming: 在Blazor应用程序中,可以使用JSInterop来调用JavaScript代码。JSInterop允许您在C#代码中调用JavaScript函数,从而使您能够使用XMLHttpRequest对象从服务器下载文件。您可以在以下几个步骤中完成此操作:

创建一个JavaScript函数,该函数使用XMLHttpRequest对象从服务器下载文件。您可以使用XMLHttpRequest对象来下载文件并将其存储在本地计算机上的任何位置。
例如,以下JavaScript函数可以使用XMLHttpRequest对象从服务器下载文件:

function downloadFile(url, filename) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';

xhr.onload = function() {
var a = document.createElement('a');
a.href = window.URL.createObjectURL(xhr.response);
a.download = filename;
a.style.display = 'none';
document.body.appendChild(a);
a.click();
a.remove();
};

xhr.send();
}
这个JavaScript函数将在XMLHttpRequest对象的onload事件触发时下载文件。它创建一个HTML链接元素,将链接元素的href属性设置为一个Blob URL,然后使用download属性指定文件名。最后,它将链接元素添加到文档中,触发单击事件来下载文件,然后将链接元素从文档中删除。

在Blazor应用程序中创建一个JavaScriptInterop类,该类使用JSInterop来调用JavaScript函数。您可以将此类注入到您的组件中,以便您可以在C#代码中使用它。
例如,以下JavaScriptInterop类将调用上述JavaScript函数:

public class DownloadService
{
private readonly IJSRuntime jsRuntime;

public DownloadService(IJSRuntime jsRuntime)
{
    this.jsRuntime = jsRuntime;
}

public async Task DownloadFileAsync(string url, string filename)
{
    await jsRuntime.InvokeVoidAsync("downloadFile", url, filename);
}

}
在Blazor应用程序中使用DownloadService类来下载文件。您可以在组件中注入DownloadService类,并使用它来从服务器下载文件。
例如,以下代码演示了如何在Blazor组件中使用DownloadService类:

@page "/download"

@inject DownloadService DownloadService

<button @onclick="DownloadFile">Download File</button>

@code {
private async Task DownloadFile()
{
await DownloadService.DownloadFileAsync("/api/download/myfile.pdf", "myfile.pdf");
}
}
这个组件在点击按钮时将调用DownloadFile方法。DownloadFile方法将使用注入的DownloadService对象来调用DownloadFileAsync方法,并传递URL和文件名参数。下载将在浏览器中自动开始,并将文件保存到本地计算机上的默认下载目录中。

请注意,您需要将XMLHttpRequest对象与您的Web服务器交互,以便下载文件。在Blazor应用程序中,您可以使用Blazor WebAssembly或Blazor Server模型。如果您使用Blazor WebAssembly模型,XMLHttpRequest对象将直接与您的Web API交互。如果您使用Blazor Server模型,则需要将XMLHttpRequest对象发送到Web服务器,然后将文件下载到客户端

支持(0) 反对(0) Technologyforgood | 园豆:6170 (大侠五级) | 2023-03-28 22:00

@Technologyforgood: /api/download/myfile.pdf 这个地址从那儿来

支持(0) 反对(0) Adming | 园豆:119 (初学一级) | 2023-03-28 22:07

你这个实现的前提是在服务器上有这个静态文件吧。
如果服务器上有文件,就不用这么麻烦,直接用Js库 Axios、 jquery ajax 甚至直接浏览器输入这个地址就可以下载来,走http通道。
我现在的问题是,在Blazor这种单页面应用中没有办法暴露一个独立的URL地址出来供客户端下载。

支持(0) 反对(0) Adming | 园豆:119 (初学一级) | 2023-03-28 22:16
0

自已解决了

Adming | 园豆:119 (初学一级) | 2023-05-15 12:03
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册