-
Notifications
You must be signed in to change notification settings - Fork 2.1k
JsonOutputFormatter adds all closing brackets when exceptions are thrown #5413
Comments
Won't you have unmanaged resourced just hanging out there un-disposed then? |
@gdoron I inspected JsonTextWriter and it doesn't use any unmanaged resources, and even if it did it should use SafeHandles to track/clean them. |
@Tratcher I hate when classes without unmanaged resources implement |
@JamesNK any thoughts on this issue? |
It's dumb behavior that I wrote about 10 years ago and I'd love to change it, but I've always worried about people who unknowingly relying on it being broken by the change. |
Oh dear. For MVC it'd also be a breaking change to stop doing this. Could Json.NET have an option for this that could be configured through MVC's JSON configuration options? E.g. JsonSerializerSettings or whatnot? |
It's not even obvious how you would change Json.Net for this, the JsonTextWriter doesn't know an exception has occurred, only that the using block has closed. The proposal above does not require changes to Json.Net. |
@gdoron we take breaking changes very seriously and it's not clear what the benefit is of making this breaking change compared to leaving it as-is. |
Leaving it as is means most people will still have the existing behavior-bug... Just my two cents. |
@gdoron thanks, we'll definitely consider this, but the bar for breaking changes is very high. We just want to make sure we make the right decision here... because if we don't, we'll have to make another breaking change to undo it 😄 |
@Tratcher @JamesNK @Eilon @gdoron What i have found on a Mac using Kestrel is that when there are exceptions thrown part way through object serialization, (unless i use the AspNetCore.Buffering middleware) i receive a 200 OK response with valid Json, but missing the remaining data and the chunked terminator. If this change were made (brackets left open) then i would still get a 200 OK, but with invalid Json and a missing chunked terminator, so still a broken response, just broken in a slightly different way. Basically what i am saying is that this change wouldn't solve the main issue of the 200 OK status code, it does not solve the original issue that started this thread which is now here: |
@chrisckc The 200 can only be changed by buffering the serialized content. Changing the serializer to avoid closing the brackets is one way to make the error more discoverable. Fixing aspnet/IISIntegration#39 is another way, but will only help some clients. |
Fixing aspnet/IISIntegration#39 would at least fix the problem in Google Chrome and PowerShell's Invoke-WebRequest based on the investigation I did for aspnet/IISIntegration#285. Are you aware of any client that would accept a response with a missing chunked terminator? That would be surprising. |
@Tratcher Understood, and i agree that not closing off the brackets and so making the Json invalid will make the error easier to discover and prevent client libraries and dev tools such as postman from interpreting the response and completely successful (clients that are not bothered about the missing chunked terminator) @halter73 I have yet to test some clients for the effect of the chunked terminator, ill get onto it soon. |
@halter73 I'm not aware of any, but parsers that reach the end of the data struct (e.g. closing brackets) may not continue reading to notice the missing terminator. |
Ok, i have tried AspNet WebApi Client and found that it correctly throws an exception with the missing chunked terminator
If I try curl from the terminal i get: curl: (18) transfer closed with outstanding read data remaining The client repo is here: https://github.com/chrisckc/TodoApiClientDemo The above demo client points to my other demo repo that demonstrates the serialization issue: https://github.com/chrisckc/TodoApiDemo Ill check my favourite iOS client library later. |
I'm testing a fix for aspnet/IISIntegration#39 and found that Chrome has stopped showing an error on the page for truncated responses, they are only shown in the dev console. That makes fixing this issue more important. IE still shows an error for truncated content. |
Does chrome actually show the truncated content though. In my testing, Chrome showed a blank page when hitting Kestrel directly, but nothing when going through IIS (along with the error in the dev console). |
It's showing truncated content now. Note I only tested text/plain. |
It also shows the truncated content for text/html and applicaiton/json. I can only hope the JS APIs are better behaved. |
Hit again: dotnet/aspnetcore#1834 |
@Tratcher Ok i have done some testing with various clients against my .Net Core WebApi method which creates the serialisation exception, and always returns a 200 status despite the exception occurring (due to the chucked transfer mechanics), here are the results: Test1 (plain old Chrome): Test2 (Javascript Fetch): Test3 (iOS): Test4 (Xamarin AndroidClientHandler): Summary @Eilon as for preventing the JSON from being closed out when an exception occurs, this would solve the issue for Test4.1 above because response.Content.ReadAsAsync() would fail with an exception. But it would still end up causing confusion for consumers of an Api as the error would not point to the real issue unless you were fully aware of how the backend WebApi works and is configured etc. |
@Tratcher @halter73 @Eilon I have just edit this post because i have realised what the issue was. I was re-checking what i found previously using HttpClient in a .Net Core console App: Ok, i have tried AspNet WebApi Client and found that it correctly throws an exception with the missing chunked terminator I have since updated to the latest .Net Core a few days ago on my Mac (dotnet --version = 1.0.0-preview3-003221) and the behaviour from a console App is the same, i thought it had changed but i had made a typo in the url when testing. One observation to make is that if the behaviour of curl changes in future OSX versions it would result in a change of behaviour of the HttpClient on OSX as it is clearly using curl under the hood from what i observed when i first tried. At least the exception you get on OSX (and Linux i assume would use curl?) is better than what i see on Windows, using HttpClient on OSX i get this, notice "Transferred a partial file" which points to the issue:
On windows i get this which does not point to the issue (in usual windows style i'm afraid to say...)
|
I have created a RequestLogging middleware and whilst testing it I have found a way to capture serialization errors by wrapping the call to the next middleware "await _next.Invoke(context)" in a try catch block. It allows the errors to be logged on the backend which is better than nothing.
I was curious to see if i could append some text to the response body using middleware by using code such as this after await _next.Invoke(context);
It had no effect, I also tried it in context.Response.OnCompleted(() and it has no effect. |
@Tratcher @halter73 @Eilon I have done some further testing with HttpClient and found something interesting, i thought if the backend can use unbuffered responses then why not make the client unbuffered and return the response as soon as the headers have been received. So i changed the code in my .Net Core test client to this: @Tratcher I can only hope the JS APIs are better behaved. Well it seems .Net's own client is not always well behaved. :-o Btw. if i use I updated the repo with this new code: |
There is a new property on JsonWriter to control this - JamesNK/Newtonsoft.Json@55afb9a - and it is testable in this pre-release package - https://www.nuget.org/packages/Newtonsoft.Json/9.0.2-beta2 |
@JamesNK super awesome, thanks for adding the feature! I suspect that in ASP.NET Core 2.0 we'll want to enable that feature by default, so once there's a public "RTM" build of 9.0.2 I think we'll want to take a dependency on that. |
@kichalla can you try out the beta and see if it gets us the the results we want? |
A new release version of Json.net was made available today. Thanks @JamesNK |
I was trying to write some tests in MVC with the new JSON.Net package but noticed that the types BsonReader and BsonWriter have been moved to its own package (but renamed to BsonDataReader and BsonDataWriter), but this package is still in pre-release which means we cannot use it yet. |
FYI: BSON package was made out of pre-release today. Thanks @JamesNK |
RE: aspnet/IISIntegration#285
When there are exceptions thrown part way through object serialization the output incorrectly closes out all of the
}
, making the serialized result appear complete/valid rather than truncated.Repro (reduced from JsonOutputFormatter):
Expected output:
{"A":"A"
Actual output:
{"A":"A"}
Recommended fix:
Remove the using statement around the JsonTextWriter and only call Close on it if the serialization completes successfully.
The text was updated successfully, but these errors were encountered: