我有一个 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 ?有没有更好的方法来实现这个目标?
Task.Run
是您的主要问题:您没有等待它,因此外部函数将在完成之前结束。因此流在此时被处理。
要么等待结果
Task
,要么根本不使用它并直接使用 await
调用这些函数。
或者,如果您确实需要将该代码保留在主线程之外,请先将文件复制到 MemoryStream 中,然后再进行缓存。
另请注意,您的缓存系统和
Task.Run
很容易在没有警告的情况下关闭,因为 ASP.Net 不保证后台任务将继续,除非您使用 BackgroundService
。