【发布时间】:2021-11-01 17:38:08
【问题描述】:
我已阅读主题:ASP.NET Core : Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead 但对于我的情况,我无法理解,如何解决它:
我有控制器方法:
public async Task<IActionResult> Upload()
{
var boundary = MultipartRequestHelper.GetBoundary(MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit);
var reader = new MultipartReader(boundary.ToString(), HttpContext.Request.Body);
var section = await reader.ReadNextSectionAsync();
List<FileApi> uploadedFiles = new List<FileApi>();
while (section != null)
{
ContentDispositionHeaderValue contentDisposition;
var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition);
if (hasContentDispositionHeader)
{
if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition))
{
var fileDto = await _zendeskManageFileService.UploadFileAsync(contentDisposition.FileName.ToString(), section.Body);
uploadedFiles.Add(_mapper.Map<FileApi>(fileDto));
}
else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition))
{
var errorNoFile = new ErrorResponse
{
Error = new Error
{
Code = "NoFile",
Message = $"Expected a file, no form data content",
}
};
return BadRequest(errorNoFile);
}
}
section = await reader.ReadNextSectionAsync();
}
return Created("", uploadedFiles);
}
当有 2 个或更多文件时,我在线上的第二个文件出现异常:
var fileDto = await _zendeskManageFileService.UploadFileAsync(contentDisposition.FileName.ToString(), section.Body);
UploadFileAsync 的代码如下:
public async Task<FileDto> UploadFileAsync(string filename, Stream stream)
{
if (stream.Position != 0)
stream.Position = 0;
var upload = await _zendeskClient.Attachments.UploadAsync(filename, stream);
FileDto fileDto = new FileDto
{
Id = upload.Id,
ContentType = upload.Attachment.ContentType,
Token = upload.Token,
ContentUrl = upload.Attachment.ContentUrl,
FileName = upload.Attachment.FileName,
Size = upload.Attachment.Size
};
return fileDto;
}
public async Task<Upload> UploadAsync(
string fileName,
Stream inputStream,
string token = null,
CancellationToken cancellationToken = default(CancellationToken))
{
var attachmentResponse = await ExecuteRequest(async (client, canToken) =>
await client.PostAsBinaryAsync(
UploadsResourceUri + $"?filename={fileName}&token={token}",
inputStream,
fileName,
canToken)
.ConfigureAwait(false),
"UploadAsync",
cancellationToken)
.ThrowIfUnsuccessful("attachments#upload-files", HttpStatusCode.Created)
.ReadContentAsAsync<UploadResponse>();
return attachmentResponse.Upload;
}
public static async Task<HttpResponseMessage> PostAsBinaryAsync(
this HttpClient client,
string requestUri,
Stream inputStream,
string fileName,
CancellationToken cancellationToken = default(CancellationToken))
{
using (var stream = new MemoryStream())
{
inputStream.CopyTo(stream);
using (var content = new ByteArrayContent(stream.ToArray()))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/binary");
return await client.PostAsync(
requestUri,
content,
cancellationToken)
.ConfigureAwait(false);
}
}
}
internal static async Task<T> ReadContentAsAsync<T>(
this Task<HttpResponseMessage> response,
JsonConverter converter = null)
where T : class
{
var unwrappedResponse = await response;
if (unwrappedResponse == null)
return null;
if (converter == null)
{
return await unwrappedResponse
.Content
.ReadAsAsync<T>();
}
return await unwrappedResponse
.Content
.ReadAsAsync<T>(converter);
}
protected async Task<HttpResponseMessage> ExecuteRequest(
Func<HttpClient, CancellationToken, Task<HttpResponseMessage>> requestBodyAccessor,
string scope,
CancellationToken cancellationToken = default(CancellationToken))
{
using (LoggerScope(Logger, scope))
using (var client = ApiClient.CreateClient())
{
return await requestBodyAccessor(client, cancellationToken);
}
}
我尝试创建和使用属性来设置AllowSynchronousIO = true
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class AllowSynchronousIOAttribute : ActionFilterAttribute
{
public AllowSynchronousIOAttribute()
{
}
public override void OnResultExecuting(ResultExecutingContext context)
{
var syncIOFeature = context.HttpContext.Features.Get<IHttpBodyControlFeature>();
if (syncIOFeature != null)
{
syncIOFeature.AllowSynchronousIO = true;
}
}
}
但这无济于事。我的情况如何解决这个问题?
堆栈错误是:
System.InvalidOperationException:同步操作是 不允许。改为调用 ReadAsync 或将 AllowSynchronousIO 设置为 true。 在 Microsoft.AspNetCore.Server.IIS.Core.HttpRequestStream.Read(字节 [] 缓冲区,Int32 偏移量,Int32 计数)在 Microsoft.AspNetCore.Server.IIS.Core.WrappingStream.Read(字节 [] 缓冲区,Int32 偏移量,Int32 计数)在 Microsoft.AspNetCore.WebUtilities.BufferedReadStream.EnsureBuffered(Int32 minCount) 在 Microsoft.AspNetCore.WebUtilities.MultipartReaderStream.Read(字节 [] 缓冲区,Int32 偏移量,Int32 计数)在 System.IO.Stream.CopyTo(流目标,Int32 bufferSize)在 System.IO.Stream.CopyTo(流目的地)在 ZendeskApi.Client.Extensions.HttpRequestExtensions.PostAsBinaryAsync(HttpClient 客户端,字符串 requestUri,流 inputStream,字符串文件名, CancellationToken 取消令牌)在 C:\www\TMS\Libraries\ZendeskApi.Client\Extensions\HttpRequestExtensions.cs:line 75 在 ZendeskApi.Client.Resources.AttachmentsResource.c__DisplayClass4_0.
d.MoveNext() 在 C:\www\TMS\Libraries\ZendeskApi.Client\Resources\AttachmentsResource.cs:line 45 --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 ZendeskApi.Client.Resources.AbstractBaseResource 1.ExecuteRequest(Func3 requestBodyAccessor,字符串范围,CancellationToken 取消令牌)在 C:\www\TMS\Libraries\ZendeskApi.Client\Resources\AbstractBaseResource.cs:line 41 在 ZendeskApi.Client.Extensions.HttpResponseExtensions.ThrowIfUnsuccessful(预期任务1 response, String helpDocLink, Nullable1,字符串 helpDocLinkPrefix) 在 C:\www\TMS\Libraries\ZendeskApi.Client\Extensions\HttpResponseExtensions.cs:line 90 在 ZendeskApi.Client.Extensions.HttpResponseExtensions.ReadContentAsAsync[T](Task`1 响应,JsonConverter 转换器)在 C:\www\TMS\Libraries\ZendeskApi.Client\Extensions\HttpResponseExtensions.cs:line 45 在 ZendeskApi.Client.Resources.AttachmentsResource.UploadAsync(字符串 文件名、流输入流、字符串令牌、CancellationToken 取消令牌)在 C:\www\TMS\Libraries\ZendeskApi.Client\Resources\AttachmentsResource.cs:line 44 在 Tms.ZendeskCore.Services.ZendeskManageFileService.UploadFileAsync(字符串 文件名,流流)在 C:\www\TMS\Libraries\Tms.ZendeskCore\Services\ZendeskManageFileService.cs:line 24 在 Tms.WebApi.Controllers.Support.ManageFileApiController.Upload() 在 C:\www\TMS\Web\Tms.WebApi\Controllers\Support\ManageFileApiController.cs:line 86 在 Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper 映射器,ObjectMethodExecutor 执行器,对象控制器,Object[] 论据)在 Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Logged|12_1(ControllerActionInvoker 调用者)在 Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker 调用者,任务 lastTask,下一个状态,作用域范围,对象状态,布尔值 已完成)在 Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed 上下文)在 Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(状态& next, Scope& 范围, Object& 状态, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|13_0(ControllerActionInvoker 调用者,任务 lastTask,下一个状态,作用域范围,对象状态,布尔值 已完成)在 Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|19_0(ResourceInvoker 调用者,任务 lastTask,下一个状态,作用域范围,对象状态,布尔值 已完成)在 Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged|17_1(ResourceInvoker 调用者)在 Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(端点 端点,任务 requestTask,ILogger 记录器)在 Microsoft.AspNetCore.Builder.Extensions.MapWhenMiddleware.Invoke(HttpContext 上下文)在 Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext 上下文)在 Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext 上下文)在 Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext 上下文)标题 ======= Accept: / Accept-Encoding: gzip, deflate, br Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...7KlZaAycWieBAvkk2WUuTkI_UqNu9IzUhk0JAeLQkvU 缓存控制:无缓存连接:保持活动内容长度:114796 内容类型:multipart/form-data; 边界=--------------271301571241092277677258 主机: 本地主机:44373 用户代理:PostmanRuntime/7.28.3 邮递员令牌: 4fd12960-9bae-45f5-8ae1-e4a5080b887b
【问题讨论】:
-
什么是堆栈跟踪?我的 猜测 是
section.Body流正在与同步 API 一起使用;section上是否有管道 API?你能缓冲一下吗?等 -
@MarcGravell 添加
-
嘿,“称之为”:p OK;所以:您要么需要执行以下操作之一:a) 使用管道 API 而不是
Stream,b) 手动缓冲数据,或 c) 启用同步 IO;有没有接受管道阅读器的上传 API?
标签: c# asynchronous file-upload