从另一个 Context 获取 IFormFile.CopyTo 时获取 ObjectDisposeException

问题描述 投票:0回答:1

我有一个 mvc 核心应用程序,正在上传和处理 .xlsx 文档。我想进行初始 POST 调用,创建一个新的异步任务来完成处理工作,而 post 调用则返回一个 GUID。然后我定期检查过程是否完成并向我返回结果。

在执行 IFormFile.CopyTo 时,我遇到了“FileBufferingReadStream”的处置问题(也尝试过 CopyToAsync)。

这是我启动新任务的控制器:

'''

[ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status409Conflict)]
[HttpPost]
[RequestFormLimits(MultipartBodyLengthLimit = 209715200)]
[RequestSizeLimit(209715200)]
[SetIdentity]
public async Task<IActionResult> Post([FromForm] UploadRequestOptions value, [FromServices] 
IServiceScopeFactory serviceScopeFactory)
{
    var requestId = Guid.NewGuid().ToString();
   try
   {
       try
       {
           var caller = User.FindFirst(ClaimTypes.NameIdentifier)?.Subject;
           value.UserId = caller.Name;

           /Attempt #1 of trying to fix dispose issue
           //cache the file and retrieve it in UploadBom method
           var file = value.File; 
           var cachedFile = new Tuple<string, IFormFile>(requestId, file);
           await _cache.SetAsync(requestId, cachedFile);

           Task.Run(async () =>
           {    
              using var scope = serviceScopeFactory.CreateScope();
              var upService = scope.ServiceProvider.GetRequiredService<IBomUploadService>();
              await upService.UploadBom(value, requestId);
           });
    }
    catch (ValidationException ex)
    {
        _logger.LogError(ex, ex.ToString());
        return StatusCode(409, ex.Message);
    }

    return Ok(requestId);
 }
 catch (Exception ex)
 {
     _logger.LogError(ex, ex.ToString());
     return StatusCode(500, ex.Message);
 }
}

'''

在我的服务中我有这个:

'''

    public async Task<int> UploadBom(UploadRequestOptions options, string requestId)
    {
      try
      {
        //Attempt #1 - retrieve cached file
        var cachedFile = await _cache.GetAsync<Tuple<string, IFormFile>>(requestId);
        var File = cachedFile.Item2;
    
         using (var memoryStream = new MemoryStream())
         {
           //Here I get: : 'Cannot access a disposed object.                                 
           //Object name: 'FileBufferingReadStream'.'
           await File.CopyToAsync(memoryStream); 

           if (reader.LoadFile(memoryStream, "Tab1"))
           {
             result.Tab1Exists = true;
             result = await tabValidator.ValidateTabAsync(reader);
           }
           else
           {
             result.Tab1Exists = false;
           }
         }
       }
    }

'''

这是我得到的 StackTrace:

'''

     at
     Microsoft.AspNetCore.WebUtilities
    .FileBufferingReadStream.ThrowIfDisposed()
     at 

     Microsoft.AspNetCore.WebUtilities
     .FileBufferingReadStream.set_Position(Int64 value)
   at Microsoft.AspNetCore.Http.ReferenceReadStream..ctor(Stream inner, 
   Int64 offset, Int64 length)
   at Microsoft.AspNetCore.Http.FormFile.OpenReadStream()
   at Microsoft.AspNetCore.Http.FormFile.CopyTo(Stream target)
   at Hamilton.Api.Services.BomUploadService.<UploadBom>d__6.MoveNext() in 
    C:\Development\Work Code\api\new-hamilton- 
    api\HamiltonAPI\Services\BomUploadService.cs:line 79

'''

有没有办法初始化它或在新的上下文中使用 CopyTo ?有没有更好的方法来实现这个目标?

c# asp.net-mvc-5
1个回答
0
投票

Task.Run
是您的主要问题:您没有等待它,因此外部函数将在完成之前结束。因此流在此时被处理。

要么等待结果

Task
,要么根本不使用它并直接使用
await
调用这些函数。

或者,如果您确实需要将该代码保留在主线程之外,请先将文件复制到 MemoryStream 中,然后再进行缓存。

另请注意,您的缓存系统和

Task.Run
很容易在没有警告的情况下关闭,因为 ASP.Net 不保证后台任务将继续,除非您使用
BackgroundService

© www.soinside.com 2019 - 2024. All rights reserved.