将excel上传到azure blob无法流式传输IFormFile

Wil*_*pez 2 c# azure azure-storage-blobs .net-core

概述:通过dotnet core 2.0 MVC将Excel电子表格上传到azure blob存储.尝试流式传输文件时,会发生错误,以便将其保存到存储中.using (var stream = new FileStream(file.FileName, FileMode.Open))(下面的代码 - _employerFileAzureService.SaveBlobAsync).

我已经回顾了几个与此相关的SO问题,但无法从中找到解决方案.

我已经能够验证以下内容:

  • 所选文件正从浏览器发送到控制器
  • 正确创建(C#)blob容器

错误

  Could not find file 'C:\dev\tfs\Admin.Web\employer-bad.test.xlsx'.
Run Code Online (Sandbox Code Playgroud)

控制器呼叫

  public async Task<IActionResult> Upload(IList<IFormFile> files, CancellationToken cancellationToken)
    {
        var result = new UploadResultViewModel();
        var processResult = new FileProcessingResult();

        var errorMessage = new StringBuilder();
        var fileName = string.Empty;
        var withError = false;

        foreach (var file in files)
        {
            try
            {
                fileName = file.FileName;
                processResult =  await ProcessUploadFiledAsync(file, cancellationToken);
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Error processing uploaded xslx");
                errorMessage.Append($"File: {fileName} errored. Error: {e.Message}");
                ModelState.AddModelError("", $"Error uploading file: {fileName} ");

            }
        }
Run Code Online (Sandbox Code Playgroud)

在容器中设置blob(失败_employerFileAzureService.SaveBlobAsync)

   private async Task<FileProcessingResult> ProcessUploadFiledAsync(IFormFile file, CancellationToken cancellationToken)
    {
        var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Value.Trim('"');
        fileName = RandomizeFileName(fileName);

        var eins = new Dictionary<string, string>();
        var result = await _employerFileAzureService.SaveBlobAsync(fileName, file);
   ...
Run Code Online (Sandbox Code Playgroud)

_employerFileAzureService.SaveBlobAsync

  public async Task<string> SaveBlobAsync(string fileName, IFormFile file)
    {
        try
        {
            var container = await _azureStorageConfigurator.GetBlobContainerAsync();
            var blobBlock = container.GetBlockBlobReference(fileName);

            using (var stream = new FileStream(file.FileName, FileMode.Open))
            {
                await blobBlock.UploadFromStreamAsync(stream);
            }

            var blobUrl = blobBlock.Uri.AbsolutePath;

            return $"{_azureStorageConfigurator.BaseStorageUri}{blobUrl}";
        }
        catch (Exception ex)
        {
            _logger.LogError($"*** Error Saving to storage: {ex.Message}");
            throw;
        }
    }
Run Code Online (Sandbox Code Playgroud)

小智 7

我怀疑这可能是因为你试图用file.FileName构造一个FileStream,我认为它只是来自客户端POV的原始文件的名称或路径.您将不得不使用IFormFile的流.

您可以尝试首先将流复制到Web服务器上的临时文件,如以下示例所示:https://docs.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads

像这样:

var tempPath = Path.GetTempFileName();

using (var stream = new FileStream(tempPath, FileMode.Create)){
    await file.CopyToAsync(stream);
}
using (var stream = new FileStream(tempPath, FileMode.Open)){
    await blobBlock.UploadFromStreamAsync(stream);
}
Run Code Online (Sandbox Code Playgroud)

或者您可以使用file.OpenReadStream()直接传递流

  • @Michael_Jagroep然而,这就成了伎俩,使用本地temp来缓慢放慢速度,但是`OpenReadStream`是要走的路,现在它很快.非常感激! (2认同)