Я настроил веб-приложение dotnet core 5, чтобы запретить синхронные операции ввода-вывода, например:
hostBuilder.ConfigureServices(services =
{
services.Configure<KestrelServerOptions>(options =>
{
options.AllowSynchronousIO = false;
});
...
}
);
Затем я создал StreamWriter, записал некоторые данные и попытался очистить их асинхронно, вот так:
var body = httpContext.Response.Body;
using var writer = new StreamWriter(body, encoding: Encoding.UTF8, leaveOpen: true);
// This performs great!
await writer.WriteAsync(...some data...);
// This throws an exception
await writer.FlushAsync();
Но я получаю это исключение при попытке выполнить очистку асинхронно, именно при вызове await writer.FlushAsync()
:
System.InvalidOperationException: Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead.
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpResponseStream.Flush()
at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
at System.IO.StreamWriter.Dispose(Boolean disposing)
at System.IO.StreamWriter.Close()
at Keep.Paper.Design.Serialization.DesignSerializer.SerializeAsync[T](Stream output, T object, CancellationToken stopToken)
at Keep.Paper.Design.Serialization.DesignSerializer.SerializeAsync[T](Stream output, T object, CancellationToken stopToken)
at Keep.Paper.Design.Rendering.OutputExtensions.WriteAsync(IOutput out, IResponse res, CancellationToken stopToken)
at Keep.Paper.Design.Rendering.RenderingPipeline.<>c__DisplayClass2_0.<<RenderAsync>b__0>d.MoveNext()
--- End of stack trace from previous location ---
at Keep.Paper.Design.Modeling.ObjectRenderer.RenderAsync(IDesignContext ctx, IRequest req, IOutput out, NextAsync next)
at Keep.Paper.Design.Rendering.RenderingPipeline.<>c__DisplayClass2_0.<<RenderAsync>b__0>d.MoveNext()
--- End of stack trace from previous location ---
at Keep.Paper.Design.Rendering.RenderingPipeline.RenderAsync(IDesignContext ctx, IRequest req, IOutput out)
Похоже, что StreamWriter.FlushAsync
вызывает под капотом Stream.Flush
, вместо того, чтобы вызывать Stream.FlushAsync
.
Я могу гарантировать, что StreamWrite.WriteAsync
действительно записывает данные в базовый поток, потому что я могу видеть данные в браузере, когда я опускаю FlushAsync
.
Но боюсь, что могу потерять некоторые данные, не вызывая FlushAsync.
Я что-то упустил? Я делаю что-то неправильно?
Пожалуйста, опубликуйте полную трассировку стека, она кажется неполной.
Я не думаю, что FlushAsync
- это то, что бросает. Это Dispose
, вызываемый блоком using
, который заканчивается на этой строке, так что да, вам нужно как-то вызвать DisposeAsync
(как показывает @GuruStron)
Я выложил сейчас полный стек. Глядя на это, вы правы, проблема не во FlushAsync, а в использовании блока, вызывающего Dispose. await using
сделал свое дело, и теперь он работает, теперь вызывается DisposeAsync.
Ради эксперимента - попробуйте
await using var writer = new StreamWriter ....