-
Notifications
You must be signed in to change notification settings - Fork 10k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Announcement] AllowSynchronousIO disabled in all servers #7644
Comments
As-per dotnet/AspNetCore.Docs#10983, will this be back ported to 2.x's feature set? Currently setting this to false in 2.2 breaks response compression. |
No, it won't be back ported. It's a massive breaking change. |
Note response compression was fixed in 3.0 using the new DisposeAsync API. |
I have been working on porting an angularJS app to .Net Core and just upgraded to Preview 3. After upgrade some of the client GET requests now blow with this error: InvalidOperationException: Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead. I don't get it because by default the angular requests are async and why do just some of them break? I am using VS 2019 Preview and will be hosting IIS in process. Any ideas? |
@GusBeare what's the full stack trace? |
I get the following html in the response. |
This change in .NET 3.0 Preview 5 breaks the usage of Reference dotnet/coreclr#24643 |
@Kaelum you should asynchronously pre-buffer the request body in this case. That's how MVC handles it: |
@Tratcher the Works, but I have concerns with caching to the file system, and the constructor in your example doesn't exist: using (FileBufferingReadStream readstream = new FileBufferingReadStream(request.Body, memoryThreshold, null, @"D:\Temp\", ArrayPool<byte>.Shared))
{
await readstream.DrainAsync(CancellationToken.None);
readstream.Seek(0L, SeekOrigin.Begin);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(XmlRequestBcap));
xmlRequestBcap = xmlSerializer.Deserialize(readstream) as XmlRequestBcap;
} Works, but probably non-performant: using (StreamReader streamReader = new StreamReader(request.Body, Encoding.UTF8))
using (StringReader stringReader = new StringReader(await streamReader.ReadToEndAsync()))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(XmlRequestBcap));
xmlRequestBcap = xmlSerializer.Deserialize(stringReader) as XmlRequestBcap;
} Does not work, executes synchronously: using (BufferedReadStream readstream = new BufferedReadStream(request.Body, memoryThreshold))
{
if (!await readstream.EnsureBufferedAsync(CancellationToken.None))
{
throw new InvalidOperationException("Request body is empty.");
}
XmlSerializer xmlSerializer = new XmlSerializer(typeof(XmlRequestBcap));
xmlRequestBcap = xmlSerializer.Deserialize(readstream) as XmlRequestBcap;
} Variation of above that works, adding a MemoryStream, but is it safe and performant: using (BufferedReadStream readstream = new BufferedReadStream(request.Body, memoryThreshold))
{
if (!await readstream.EnsureBufferedAsync(CancellationToken.None))
{
throw new InvalidOperationException("Request body is empty.");
}
using (MemoryStream memoryStream = new MemoryStream(readstream.BufferedData.Array, readstream.BufferedData.Offset, readstream.BufferedData.Count, false))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(XmlRequestBcap));
xmlRequestBcap = xmlSerializer.Deserialize(memoryStream) as XmlRequestBcap;
}
} If Thanks! |
It's there AFAIK. |
@davidfowl & @Tratcher I just verified that it is not in the C:\Program Files\dotnet\packs\Microsoft.AspNetCore.App.Ref\3.0.0-preview5-19227-01\ref\netcoreapp3.0\Microsoft.AspNetCore.WebUtilities.dll When I disassemble that assembly, I can very definitely see only 4 constructors, with the 2 parameter constructor missing. |
Here's the MVC PR: #9806 |
@Tratcher But I still get the same error message: Do I have to do something special by using the |
What's the stack trace? |
How are you creating TestServer in your test? The old pattern was to do The new pattern looks like this and would work with DI options: |
…O call from ASP.NET dotnet/aspnetcore#7644 Fix issue on .Net Core 3.0 regression dotnet/aspnetcore#17973
@pranavkm We are hitting this issue with
results sometimes, but non-deterministically (afaics) in an InvalidOperationException with
are we using the API incorrectly or should we create a new issue for this? |
You're only doing a single ReadAsync on the body, you need to read until the end of the body to ensure it's fully buffered. Read in a loop until it returns 0. |
If I understand this change correctly, I appreciate it. But I am not clear on how to pre-buffer the request body to access it in other parts of asp.net. I implemented my own HMAC Authentication Handler that I add with services.AddAuthentication(). I want to confirm that the body has not been tampered with in transit, so I include request body as input to encryption token on the client and then do the same thing on the server to verify its integrity. The problem is that I can't read Request.Body in the server Authentication Handler method since reading the stream directly can interfere with the rest of the pipeline. It would be nice if there was a simple switch that you can use in Startup to automatically buffer every request before sending anything down the pipeline. That way Authentication Handlers or whatever else you want to use have access to the entire Request Body before handlers are ever executed. Is this possible? The only examples I find when I search for pre-buffering Request.Body talk about doing it inside the controller method. Clearly, that's not helpful because anything in Controller happens AFTER Authentication Handlers or other initiating handlers. |
HttpRequest.EnableBuffering is the simplest mechanism.
The example above mostly covered it, except that it needs to read to the end of the body.
Yes, via middleware using the example above. Note we don't recommend buffering globally or make it any easier because it has side-effects like no longer being able to override request body size limits per endpoint. |
@Tratcher lets make sure to get this documented. |
Is there a way to enable it for specific calls? We do use a third party component that does not support async calls and it feels wrong to set the whole application to |
@matthiaslischka Yes:
|
We need guidance for this, you have 2 options:
|
We have this scenario where we create a zip file for some very small files and stream it directly to the HttpContext response stream. Without drastically changing the implementation we now can
I'm not sure which one is better/cleaner. |
@matthiaslischka If the files are small then buffering to a memory stream is better. It avoids accidentally blocking threads with IO, and it will probably perform better because it will aggregate small writes from the zip library. |
Thank you for contacting us. Due to a lack of activity on this discussion issue we're closing it in an effort to keep our backlog clean. If you believe there is a concern related to the ASP.NET Core framework, which hasn't been addressed yet, please file a new issue. This issue will be locked after 30 more days of inactivity. If you still wish to discuss this subject after then, please create a new issue! |
Thank you for contacting us. Due to a lack of activity on this discussion issue we're closing it in an effort to keep our backlog clean. If you believe there is a concern related to the ASP.NET Core framework, which hasn't been addressed yet, please file a new issue. This issue will be locked after 30 more days of inactivity. If you still wish to discuss this subject after then, please create a new issue! |
AllowSynchronousIO is a option in each server that enables or disables sync IO APIs like HttpReqeuest.Body.Read, HttpResponse.Body.Write, Stream.Flush, etc.. These APIs have long been a source of thread starvation and application hangs. Starting in 3.0.0-preview3 these are disabled by default.
Affected servers:
Expect errors similar to:
Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead.
Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead.
Synchronous operations are disallowed. Call FlushAsync or set AllowSynchronousIO to true instead.
Each server has a AllowSynchronousIO option that controls this behavior and the default for all of them is now false.
The behavior can also be overridden on a per request basis as a temporary mitigation.
If you have trouble with TextWriters or other streams calling sync APIs in Dispose, call the new DisposeAsync API instead.
The text was updated successfully, but these errors were encountered: