Will Lopez
Will Lopez

Reputation: 2119

Upload excel to azure blob fails streaming IFormFile

Overview: Uploading an Excel spreadsheet to azure blob storage via dotnet core 2.0 MVC. The error occurs when trying to stream the file so that it can be saved into storage. using (var stream = new FileStream(file.FileName, FileMode.Open)) (code below - _employerFileAzureService.SaveBlobAsync).

I've reviewed several SO questions relating to this but couldn't find a solution from them.

I've been able to verify the following:

Error

  Could not find file 'C:\dev\tfs\Admin.Web\employer-bad.test.xlsx'.

Controller call

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

            }
        }

Set up blob in container (fails _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);
   ...

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

Upvotes: 3

Views: 3160

Answers (1)

Michael Jagroep
Michael Jagroep

Reputation: 161

I suspect it might be because you're trying to construct a FileStream out of file.FileName, which I think is just the name or path of the original file from the client's POV. You will have to work with the IFormFile's stream instead.

You can try copying the stream to a temporary file on the web server first, as shown in the example at: https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads

like so:

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

Or you might be able to pass the stream on directly using file.OpenReadStream()

Upvotes: 9

Related Questions