Blazor (.NET 5) 中的文件上传问题 - 处理多个文件提交

rap*_*esa 5 .net c# blazor

我正在开发一个使用 .NET 5 上传 PNG 图像的 Blazor 应用程序。该功能涉及在选择文件并随后提交后显示文件信息(大小、名称等)。

\n

一切都按预期进行,除了当我尝试提交一个又一个文件时。我遇到异常:“没有 ID 为 1 的文件。文件列表可能已更改。”

\n

这是代码的简化版本:

\n
<button @onclick="Submit">T\xc3\xa9l\xc3\xa9charger</button>\n\n@code {\n    IList<string> imageDataUrls = new List<string>();\n    List<IBrowserFile> list = new List<IBrowserFile>();\n\n    void OnInputFileChange(InputFileChangeEventArgs e)\n    {\n        var maxAllowedFiles = 3;\n        list.AddRange(e.GetMultipleFiles(maxAllowedFiles));\n    }\n\n    async Task Submit()\n    {        \n        var format = "image/png";\n        foreach (var imageFile in list)\n        {   \n            var resizedImageFile = await imageFile.RequestImageFileAsync(format,\n                100, 100);\n            var buffer = new byte[resizedImageFile.Size];\n            await resizedImageFile.OpenReadStream().ReadAsync(buffer);\n            var imageDataUrl =\n                $"data:{format};base64,{Convert.ToBase64String(buffer)}";\n            imageDataUrls.Add(imageDataUrl);\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

尝试按顺序提交多个文件时会出现此问题。我收到与更改文件 ID 相关的错误,特别是“不存在 ID 为 1 的文件。文件列表可能已更改。”

\n

我正在寻求有关如何在逐个提交文件时处理此异常以及如何在 Blazor 应用程序中避免这些与 ID 相关的问题的指导。任何帮助将不胜感激。

\n

Jus*_*nno 4

对于为什么您的解决方案不起作用,我没有一个很好的答案,但修复它很容易。似乎只有在事件处理方法中时才能访问文件内容。

\n

作为解决方法,为您的图像演示创建一个“ViewModel”类。

\n
 public class FileViewModel\n{\n        /// helpful in combination with @key to make list rendering more efficient\n        public Guid Id { get; set; }\n        public String Name { get; set; }\n        public String ContentType { get; set; }\n        public Int64 Size { get; set; }\n        public Byte[] Content { get; set; }\n        public String ImageDataUrl { get; set; }\n\n        public FileViewModel()\n        {\n            Id = Guid.NewGuid();\n        }\n\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

OnInputFileChange 的更改

\n

将您的代码与Submit合并OnInputFileChange。在事件处理期间,为每个文件创建一个 ViewModel 实例并保存实例的内容。

\n
\n    List<FileViewModel> list = new List<FileViewModel>();\n\n    private async Task OnInputFileChange(InputFileChangeEventArgs e)\n    {\n        var maxAllowedFiles = 3;\n\n        var format = "image/png";\n\n        foreach (var imageFile in e.GetMultipleFiles(maxAllowedFiles))\n        {\n            var resizedImageFile = await imageFile.RequestImageFileAsync(format,\n                100, 100);\n            var buffer = new byte[resizedImageFile.Size];\n            await resizedImageFile.OpenReadStream().ReadAsync(buffer);\n            var imageDataUrl =\n                $"data:{format};base64,{Convert.ToBase64String(buffer)}";\n\n            list.Add(new FileViewModel\n            {\n                Content = buffer,\n                ImageDataUrl = imageDataUrl,\n                ContentType = imageFile.ContentType,\n                Name = imageFile.Name,\n                Size = imageFile.Size,\n            });\n        }\n    }\n\n
Run Code Online (Sandbox Code Playgroud)\n

我添加了一个删除按钮来展示读取内容后对集合的操作。

\n

删除图像

\n
@if (list.Count > 0)\n{\n    <h4>Images</h4>\n\n    <div class="card" style="width:30rem;">\n        <div class="card-body">\n            @foreach (var file in list)\n            {\n                <img class="rounded m-1" @key="file.Id" src="@file.ImageDataUrl" />\n                <button type="button" @onclick="() => RemoveImage(file)">Remove</button>\n            }\n        </div>\n    </div>\n}\n\n\n@code {\n\n    private void RemoveImage(FileViewModel file)\n    {\n        list.Remove(file);\n    }\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

通过绕行,您现在可以完全访问 ViewModel 实例中的数据。然后您可以使用这些数据将您的文件提交给您的服务。在示例中,我记录了文件名和字节数组的长度作为概念证明。

\n
\n    async Task Submit()\n    {\n        foreach (var item in list)\n        {\n            Console.WriteLine($"file {item.Name} | size {item.Content.Length}");\n        }\n    }\n\n
Run Code Online (Sandbox Code Playgroud)\n

整个组件

\n
@page "/"\n\n<h3>Upload PNG images</h3>\n\n<p>\n    <InputFile OnChange="@OnInputFileChange" multiple />\n</p>\n\n@if (list.Count > 0)\n{\n    <h4>Images</h4>\n\n    <div class="card" style="width:30rem;">\n        <div class="card-body">\n            @foreach (var file in list)\n            {\n                <img class="rounded m-1" @key="file.Id" src="@file.ImageDataUrl" />\n                <button type="button" @onclick="() => RemoveImage(file)">Remove</button>\n            }\n        </div>\n    </div>\n}\n\n@if (list.Count() > 0)\n{\n    <div class="card" style="width:30rem;">\n        <div class="card-body">\n            @foreach (var file in list)\n            {\n                <div>@file.Name - @file.ContentType - @file.Size</div>\n            }\n        </div>\n    </div>\n}\n\n\n\n<button @onclick="Submit">T\xc3\xa9l\xc3\xa9charger</button>\n\n@code {\n\n    List<FileViewModel> list = new List<FileViewModel>();\n\n    private async Task OnInputFileChange(InputFileChangeEventArgs e)\n    {\n        var maxAllowedFiles = 3;\n\n        var format = "image/png";\n\n        foreach (var imageFile in e.GetMultipleFiles(maxAllowedFiles))\n        {\n            var resizedImageFile = await imageFile.RequestImageFileAsync(format,\n                100, 100);\n            var buffer = new byte[resizedImageFile.Size];\n            await resizedImageFile.OpenReadStream().ReadAsync(buffer);\n            var imageDataUrl =\n                $"data:{format};base64,{Convert.ToBase64String(buffer)}";\n\n            list.Add(new FileViewModel\n            {\n                Content = buffer,\n                ImageDataUrl = imageDataUrl,\n                ContentType = imageFile.ContentType,\n                Name = imageFile.Name,\n                Size = imageFile.Size,\n            });\n        }\n    }\n\n    private void RemoveImage(FileViewModel file)\n    {\n        list.Remove(file);\n    }\n\n    async Task Submit()\n    {\n        foreach (var item in list)\n        {\n            Console.WriteLine($"file {item.Name} | size {item.Content.Length}");\n        }\n    }\n\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n