Blazor文件上传解决方案

前言

Blazor 是由 Asp.Net Core 团队推出的一个Web前端SPA解决方案,其中包括了使用 WebAssembly 的 Blazor Wasm 和使用 SignalR 进行实时交互的 Blazor server。本篇文章中使用的是 Blazor Wasm 方案来验证上传文件的操作。

上传文件

在网络应用程序中,您有时需要将文件上传到服务器。这是使用 Blazor 的方法。

目前,Blazor 并没有提供开箱即用的功能,我们将不得不使用 js 加载文件内容,并使用 C# 将该内容发送到服务器。

Blazor端

您需要一个选择文件的 input 元素,并使用 Blazor/C# 来处理他的 onchange 事件。

我们将从 javascript 函数接收二进制文件作为 base64字符串,因为字节数组无法在 json 中序列化,并且这是 C# 和 js 之间的交换格式。

本实例中服务器 Webapi 只会返回保存文件的文件名,但是您可以添加其他想要返回的信息。

//依赖注入 JSRuntime
@inject IJSRuntime JSRuntime;
<input type="file" onchange="@UploadFile" id="fileUpload" @ref="fileUpload" />
<img src="@ImageSource" alt="已选择图片">
@code {
    public string ImageSource{ get; set; }
    async Task UploadFile()
    {
        // JSRuntime 实现 .Net 调用 Javascript 方法
        var data = await JSRuntime.InvokeAsync<string>("readUploadedFileAsText", fileUpload);
        //js 返回内容为:文件信息+文件 base64 字符串。将其设置为 img 标签的 src,可以预览上传的图片,上传时只需要 base64 字符串
        ImageSource = data;
        //这里直接使用 ByteArrayContent 作为 HttpBody
        var response = await Http.PostAsync("/api/upload",new ByteArrayContent(Convert.FromBase64String(data.Split(",")[1])));
        var fileTempName = await response.Content.ReadAsStringAsync();
    }
}

Javascript

添加一个获取文件内容的方法,Blazor 中调用异步 js 方法,因此我们使用 Promise 来实现 js 中异步读取文件。

Blazor 和 JavaScript 互操作可以参考 MSDN 文档:在 ASP.NET Core Blazor 中从 .NET 方法调用 JavaScript 函数

js 读取文件内容可以参考 MDN 文档:FileReader的使用,它很有帮助,除此之外还需要了解一下 Promise。FileReader 的 readAsDataURL 方法将文件信息追加到文件 base64 中,其实我们需要上传的只是后面的 base64 字符串。

window.readUploadedFileAsText = (inputFile) => {
    const temporaryFileReader = new FileReader();
    console.log(inputFile.files[0])
    return new Promise((resolve, reject) => {
        temporaryFileReader.onerror = () => {
            temporaryFileReader.abort();
            reject(new DOMException("读取文件失败"));
        };
        temporaryFileReader.addEventListener("load", function () {
            resolve(his.result);
        }, false);
        temporaryFileReader.readAsDataURL(inputFile.files[0]);
    });
};

服务器 Webapi

这是用于将文件内容保存在服务器上的代码,将二进制数组从 HttpBody 流里读取然后写入文件中。

[Route("api/upload")]
    public class UploadController : ControllerBase
    {
        [HttpPost]
        public async Task<IActionResult> Post()
        {
            var tempFileName = $"../WebProgramPath/{Guid.NewGuid().ToString()}";
            using (var writer = System.IO.File.OpenWrite(tempFileName))
            {
                await Request.Body.CopyToAsync(writer);
            }
            return Ok(Path.GetFileNameWithoutExtension(tempFileName));
        }
    }

残留问题

使用上面的代码,可以实现 Blazor 客户端上传文件到服务器,但在这个过程中我也发现,当选择的文件超过一定大小时,会引发错误:

Uncaught (in promise) RuntimeError: memory access out of bounds。

这可能由于 wasm 和 js 互操作时的共享内存规定所导致的,网上解决方案时在 wasm 打包时指定内存,但 Blazor 中没有找到合适的解决方案。

所以,我在 GitHub 提了一个 issue 给 Asp.Net Core 团队,他们回复我:团队将会在 RC1 版本中添加一个新的组件——InputFile,来避免在文件操作时开发者进行繁杂的 Js 互操作。

发布时间:2021-05-06
其他阅读

Linux中查看,添加,修改,删除用户和用户组

将用户分组是Linux系统中对用户进行管理及控制访问权限的一种手段。某个用户都属于某个用户组;一个组中可以有多个用户,一个用户也可以属于不同的组。当一个用户同时是多个组中的成员时,登录时所属的为默认组,而其他组称为附加组。本文将会介绍在 Linux 中查看,添加,修改,删除用户和用户组,注意:权限管理非常重要,可能一不小心就导致系统无法登录,请谨慎操作。

查看原文

个人简介

你好,我是猪头少年,是一名定居在云南的软件工程师,主要的开发语言为 C#JavaScript,后端使用 ASP.NET Core,桌面端使用 WPFUnity ,前端使用 AngularBabylon.js。平时喜欢自驾出游。欢迎大家联系我。

查看原文

静态文件防盗链的一种思路

在我们的系统中,总会有一些资源需要保护起来不被盗走,如果是动态接口可以通过验证权限来保护,静态资源大多需要对外开放,比较难以保护,本文就介绍保护静态文件资源一种思路——那就是使用 HTTP 中 Referer 头。

查看原文

电脑版微信支持抢红包和发朋友圈了

微信迎来史诗级加强——支持抢红包,微信迎来史诗级加强——支持发布朋友圈。

查看原文

Angular中开发一个代码库

Angular 的复杂项目中,我们可以对其拆分出不同功能模块进行开发,但是对于大型项目,或者我们直接考虑拆成库,将一部分的模块合起来组成一个库,方便复用,比如我们熟悉的各种设计组件库,就是一堆模块的合集。

查看原文