MudFileUpload分批选文件提交报错:There is no file with ID 1问题排查
问题:MudFileUpload多次单文件添加后提交报错
现象
- PC端批量选择文件后提交,API请求无报错
- 移动端(或手动多次单文件添加):每次选择1个文件、多次添加后提交,触发错误:
There is no file with ID 1. The file list may have changed.
- 单个文件提交、批量文件提交均正常,仅多次单文件添加后提交出现问题
组件代码(.razor)
<MudFileUpload T="IReadOnlyList<IBrowserFile>" FilesChanged="InsertFiles" Accept=".jpg, .png, .bmp" Style="display:contents"> </MudFileUpload> <MudButton Variant="Variant.Filled" EndIcon="@Icons.Material.Filled.Send" Color="Color.Primary" FullWidth="true" ButtonType="ButtonType.Submit" Class="btn-user ml-4" Disabled="@buttonDisabled"> Submit </MudButton>
后台代码(.razor.cs)
private IList<IBrowserFile> files = new List<IBrowserFile>(); private void InsertFiles(IReadOnlyList<IBrowserFile> files) { var fileSize = 0f; foreach (var item in files) { fileSize = totalFileSize + item.Size; this.files.Add(item); } } private async Task SubmitAsync() { try { using var content = new MultipartFormDataContent(); foreach (var file in this.files) { var fileContent = new StreamContent(file.OpenReadStream(maxFileSize)); fileContent.Headers.ContentType = new MediaTypeHeaderValue(file.ContentType); content.Add( content: fileContent, name: "\"files\"", fileName: file.Name); } var response = await mHttpService!.Post<List<UploadResult>>("api/some-end-point", content); } catch (Exception e) { Console.WriteLine(e.Message); mSnackbar!.Add($"Exception encountered: {e.Message}", Severity.Error); } }
原因分析
这个错误的核心是IBrowserFile实例和浏览器的文件引用绑定:
- 批量选择时,所有IBrowserFile实例来自同一次浏览器文件选择操作,浏览器会保持这些文件的引用,提交时可以正常读取流
- 多次单文件选择时,每次选择后MudFileUpload会更新内部的文件列表,之前选择产生的IBrowserFile实例对应的浏览器文件ID会被清除或覆盖,此时调用
OpenReadStream就会抛出文件ID不存在的错误
解决方法
方法1:提前读取文件内容到内存(适合小文件场景)
不再直接存储IBrowserFile实例,而是在添加文件时就把内容读取到内存,保存文件名、类型和字节数组:
// 新增存储文件数据的类 public class UploadFile { public string FileName { get; set; } public string ContentType { get; set; } public byte[] Content { get; set; } } private List<UploadFile> uploadFiles = new List<UploadFile>(); private void InsertFiles(IReadOnlyList<IBrowserFile> files) { foreach (var item in files) { using var stream = item.OpenReadStream(maxFileSize); using var memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); uploadFiles.Add(new UploadFile { FileName = item.Name, ContentType = item.ContentType, Content = memoryStream.ToArray() }); } } private async Task SubmitAsync() { try { using var content = new MultipartFormDataContent(); foreach (var file in uploadFiles) { var fileContent = new ByteArrayContent(file.Content); fileContent.Headers.ContentType = new MediaTypeHeaderValue(file.ContentType); content.Add( content: fileContent, name: "\"files\"", fileName: file.FileName); } var response = await mHttpService!.Post<List<UploadResult>>("api/some-end-point", content); } catch (Exception e) { Console.WriteLine(e.Message); mSnackbar!.Add($"Exception encountered: {e.Message}", Severity.Error); } }
方法2:使用MudFileUpload内置文件管理(推荐)
MudFileUpload本身支持多文件累加选择,直接使用组件的Files属性来获取有效文件列表,不需要自己维护:
修改Razor组件:
<MudFileUpload @ref="fileUpload" T="IReadOnlyList<IBrowserFile>" AllowMultiple="true" Accept=".jpg, .png, .bmp" Style="display:contents"> </MudFileUpload> <MudButton Variant="Variant.Filled" EndIcon="@Icons.Material.Filled.Send" Color="Color.Primary" FullWidth="true" ButtonType="ButtonType.Submit" Class="btn-user ml-4" Disabled="@buttonDisabled" OnClick="SubmitAsync"> Submit </MudButton>
修改后台代码:
private MudFileUpload<IReadOnlyList<IBrowserFile>> fileUpload; private async Task SubmitAsync() { try { using var content = new MultipartFormDataContent(); foreach (var file in fileUpload.Files) { var fileContent = new StreamContent(file.OpenReadStream(maxFileSize)); fileContent.Headers.ContentType = new MediaTypeHeaderValue(file.ContentType); content.Add( content: fileContent, name: "\"files\"", fileName: file.Name); } var response = await mHttpService!.Post<List<UploadResult>>("api/some-end-point", content); } catch (Exception e) { Console.WriteLine(e.Message); mSnackbar!.Add($"Exception encountered: {e.Message}", Severity.Error); } }
内容的提问来源于stack exchange,提问作者Ibanez1408
相关产品推荐
相关产品推荐

