You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
}

验证要点

  1. 上传PDF后,检查数据库中存储的varbinary(max)数据长度是否与原文件大小一致
  2. 下载后对比文件MD5值,确认与原文件完全匹配

内容的提问来源于stack exchange,提问作者osswmi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 22:45:40