Blazor服务器应用PDF下载损坏但图片正常问题排查
问题分析与修复方案
核心问题:文件上传时未完整读取流内容
PDF下载损坏的核心原因是上传阶段没有确保完整读取文件流。Stream.ReadAsync方法返回实际读取的字节数,并非一定会一次性读取完所有内容(尤其是较大的PDF文件),你直接忽略了返回值,导致SupportingDocumentData数组只填充了部分数据,最终存储到数据库的文件不完整,下载后自然损坏。图片文件体积较小,刚好被一次性读取,所以能正常打开。
另外还有两个次要问题需要修正:
- 异步方法使用
async void不符合Blazor最佳实践,会导致异常无法被正确捕获 - 文件名和扩展名的截取逻辑过于复杂,且存在潜在的边界错误
修复后的代码
1. 修正上传方法(C#)
// 把async void改为async Task,符合Blazor异步规范 public async Task OnHardwarePurchaseWarrantySupportingDocumentChange(InputFileChangeEventArgs inputFileChangeEventArgs) { try { foreach(IBrowserFile file in inputFileChangeEventArgs.GetMultipleFiles(inputFileChangeEventArgs.FileCount)) { using Stream stream = file.OpenReadStream(file.Size); // 使用using自动释放流,无需手动Close HardwarePurchaseWarrantyCreate.SupportingDocumentData = new byte[stream.Length]; // 循环读取,确保完整读取所有字节 int bytesRead; int offset = 0; while ((bytesRead = await stream.ReadAsync(HardwarePurchaseWarrantyCreate.SupportingDocumentData, offset, HardwarePurchaseWarrantyCreate.SupportingDocumentData.Length - offset)) > 0) { offset += bytesRead; } // 使用Path类简化文件名和扩展名获取,更可靠 HardwarePurchaseWarrantyCreate.SupportingDocumentName = Path.GetFileNameWithoutExtension(file.Name); HardwarePurchaseWarrantyCreate.SupportingDocumentFileExtension = Path.GetExtension(file.Name); break; } } catch (Exception fe) { Log.LogError(fe.Message, fe); Modal.ShowErrorModal("File Upload Failure", "The selected file could not be uploaded due to an error. Please try again. If the error persist, please contact support.", false, false, false, delegate {}); } finally{ Throbber.IsSpinning = false; } }
2. 修正下载方法的潜在问题(可选但推荐)
创建MemoryStream后,确保流的位置重置到起始处,避免DotNetStreamReference从流的末尾开始读取:
public async Task DownloadHardwarePurchaseWarrantySupportingDocumentData() { try { using MemoryStream memoryStream = new MemoryStream(HardwarePurchaseWarranty.SupportingDocumentData); memoryStream.Position = 0; // 重置流位置到起始点 using DotNetStreamReference memoryStreamReference = new DotNetStreamReference(stream: memoryStream); await JSRuntime.InvokeVoidAsync("window.DownloadFile", $"{HardwarePurchaseWarranty.SupportingDocumentName}{HardwarePurchaseWarranty.SupportingDocumentFileExtension}", memoryStreamReference); } catch (Exception e) { Log.LogError(e.Message); Modal.ShowErrorModal("Program Error", "Unexpected error trying to download file. If the issue persist, please contact support.", true, false, false, delegate {}); } }
3. JavaScript下载代码保持不变
你的下载逻辑本身没有问题,无需修改:
window.DownloadFile = async (fileName, contentStreamReference) => { const arrayBuffer = await contentStreamReference.arrayBuffer(); const blob = new Blob([arrayBuffer]); const url = URL.createObjectURL(blob); const anchorElement = document.createElement('a'); anchorElement.href = url; anchorElement.download = fileName ?? ''; anchorElement.click(); anchorElement.remove(); URL.revokeObjectURL(url); }
验证要点
- 上传PDF后,检查数据库中存储的
varbinary(max)数据长度是否与原文件大小一致 - 下载后对比文件MD5值,确认与原文件完全匹配
内容的提问来源于stack exchange,提问作者osswmi
相关产品推荐
相关产品推荐

