I am using Utf8 json library to deserialize my JSON using DeserializeAsync method of JsonSerializer class. And sometimes I am seeing it is throwing exception as -
Arithmetic operation resulted in an overflow.
So it looks like my JSON data has a value that's too large to fit in one of our object's properties causing this overflow exception. Below is the code I got where I am trying to print the json which is bad and causing this Arithmetic Overflow error but it's not logging that JSON whenever this exception happens.
using (var content = httpResponseMessage.Content)
{
if (content == null) return (default(T), statusCode);
using (var responseStream = await httpResponseMessage.Content.ReadAsStreamAsync())
{
try
{
deserializedValue = await JsonSerializer.DeserializeAsync<T>(responseStream, formatResolver);
}
catch (Exception ex)
{
var bodyString = (ex as JsonParsingException)?.GetUnderlyingByteArrayUnsafe();
var error = (bodyString != null) ? $"Bad json: {Encoding.UTF8.GetString(bodyString)}" : "Cannot Deserialize JSON";
logger.logError(error, ex.Message, "Deserialization Exception", ex.StackTrace, (int)statusCode);
return (default(T), HttpStatusCode.BadRequest);
}
}
}
For some reason bodyString is coming as null whenever this exception happens and that's why my condition is not getting evaluated to get the JSON body. My understanding was that it will throw JsonParsingException but looks like it is throwing some other exception.
Is there any way to get JSON body whenever this exception happens? or maybe write this in a better way to get JSON whenever this exception happens efficiently?
You wrote that you got an "Arithmetic Overflow" error, so the actual type of exception in the catch is probably OverflowException, not JsonParsingException
I think you should get bodyString from responseStream. You can reset the stream with responseStream.Position = 0 and read the body as a byte array from it.
Related
When the HttpClient throws an exception trying to get a page it returns a HttpRequestException. This exception doesn't really have anything to categorize the error apart from the message so the only way i can see to handle errors is like so:
try
{
HttpResponseMessage response = await client.GetAsync("http://www.example.com/");
// ...
}
catch (HttpRequestException e)
{
if(e.Message == "Name or service not known")
{
HandleNotKnown();
return;
}
if(e.Message == "Some other specific message")
{
HandleOtherError();
return;
}
// ... etc
}
I don't like doing this because I feel like at some point the error text could change in an update and break my code.
Is there a better way to handle specific errors with HttpClient?
The HttpRequestException inherits from Exception and so it has the InnerException property
Gets the Exception instance that caused the current exception.
So check this Exception for more details.
I made a simple app where chunks of a file are streamed from client to server. Server-side I have handled exceptions such that a response of my own is returned to the client. When I throw an exception before reading from the stream has been completed, however, even though it gets caught and a custom response is returned, client-side I still get an unhandled RpcException with status Cancelled.
public override async Task<UploadFileResponse> UploadFile(
IAsyncStreamReader<UploadFileRequest> requestStream,
ServerCallContext context)
{
try
{
bool moveNext = await requestStream.MoveNext();
using (var stream = System.IO.File.Create($"foo.txt"))
{
while (moveNext)
{
// If something goes wrong here, before the stream has been fully read, an RpcException
// of status Cancelled is caught in the client instead of receiving an UploadFileResponse of
// type 'Failed'. Despite the fact that we catch it in the server and return a Failed response.
await stream.WriteAsync(requestStream.Current.Data.ToByteArray());
moveNext = await requestStream.MoveNext();
throw new Exception();
}
// If something goes wrong here, when the stream has been fully read, we catch it and successfully return
// a response of our own instead of an RpcException.
// throw new Exception();
}
return new UploadFileResponse()
{
StatusCode = UploadStatusCode.Ok
};
}
catch (Exception ex)
{
return new UploadFileResponse()
{
Message = ex.Message,
StatusCode = UploadStatusCode.Failed
};
}
}
Perhaps the way I approach implementing this operation is wrong. I can see why the server would return a Cancelled RPC exception because we indeed cancel the call before the stream has been fully read but I don't understand why it overrides the custom response. It might be that handling both would have to be done client-side - a failed response and a potential RPC exception.
I found some materials on the topic - Server and Client.
Apparently it is common to throw RpcExceptions whenever there should be an invalid response as also shown in the official gRPC Github repository here.
When the length of characters in json result is large the following exception will be raised:
Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property.
The above exception is a server side exception with 500 response code so if we put the source code inside a try catch block, the error should be caught in catch block, but try catch does not work for this scenario.
You could test this problem by following code, please use it inside an asp.net mvc controller:
public JsonResult Test()
{
try
{
var result = "";
var v1 = new JavaScriptSerializer();
for (int i = 0; i < (v1.MaxJsonLength / 100) + 10; i++)
{
result += "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";
}
//exception message:
//Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property.
return Json(result, JsonRequestBehavior.AllowGet);
}
catch
{
//when exception is raised the catch will not be called
return null;
}
}
I cannot reproduce the error, but anyway what is happening to you is that the Json method implementation is already catching the exception internally and converting it to full-blown HTTP 5xx response. There is no exception coming out from the return Json() call.
There is no chance for you to catch the exception because... what would you do? Generate an HTTP 5xx response? That is already done for you by the MVC framework.
Try like this:
ActionResult result;
try
{
var result = "";
var v1 = new JavaScriptSerializer();
for (int i = 0; i < (v1.MaxJsonLength / 100) + 10; i++)
{
result += "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";
}
//exception message:
//Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property.
result= Json(result, JsonRequestBehavior.AllowGet);
}
catch
{
//when exception is raised the catch will not be called
}
return result;
I try to implement code for error handling from Newtonsoft Documentation
I am using the following JsonSerializerSettings
errors = new JsonErrors();
jsonSerializerSettings = new JsonSerializerSettings
{
Error = delegate (object sender, ErrorEventArgs args)
{
errors.Add(args.ErrorContext.Error.Message);
args.ErrorContext.Handled = true;
}
};
I use the following code to deserialize the response.
try
{
deserializedObject = JsonConvert.DeserializeObject(response, jsonSerializerSettings);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
If add some extra chars at the end of the response string i expect to catch deserialize exception but actually i see relevant error added to JsonErrors object.
Can i be sure that any error raised by de-serialization/serialization will be catched by JsonSerializerSettings mechanism.
Can i remove the try a catch in code?
In theory all exceptions should be caught and passed to the handler (other than exceptions that cannot be caught such as StackOverflowException.) If you go to the github source and search for IsErrorHandled you will see that all types of exception are caught, for instance here:
catch (Exception ex)
{
if (IsErrorHandled(null, contract, null, reader as IJsonLineInfo, reader.Path, ex))
{
HandleError(reader, false, 0);
return null;
}
else
{
// clear context in case serializer is being used inside a converter
// if the converter wraps the error then not clearing the context will cause this error:
// "Current error context error is different to requested error."
ClearErrorContext();
throw;
}
}
That being said, in practice there may be edge cases where this does not work. For instance, in a previous answer I noted that exceptions thrown from the OnSerializing event of the root object cannot be handled -- though this seems not to be reproducible in the current version (9.0) of Json.NET. But even in the current version, if an exception is thrown trying to create a contract for the root object, Json.NET will not catch and handle it. This could happen because of a buggy custom contract resolver, or because of a mistake in applying serialization attributes to the root object. For instance, trying to serialize or deserialize the following as the root object:
public class BadExtensionData
{
Dictionary<string, object> extensionData;
[JsonExtensionData]
public Dictionary<string, object> ExtensionData { set { extensionData = value; } }
}
will result in an unhandled exception:
Newtonsoft.Json.JsonException: Invalid extension data attribute on 'BadExtensionData'. Member 'ExtensionData' must have a getter.
Thus you may want to leave the outer try/catch just in case (and even report an issue for exceptions that cannot be handled).
Finally, do be aware that catching and swallowing all exceptions is considered bad practice.
After quick source code inspection I tend to say that following sentence is true:
If JsonSerializerSettings is proper (ie. without nasty null references and with configured error handler with Handled property set to true)
and input string is not null (only for deserialization), then try-catch block is redundant.
I am writing a unit test for a WCF web service. I am deliberately sending an invalid request to the server which throws a WebExceptionFault<string>. In the unit test, the Exception that gets caught is an EndpointNotFoundException with the standard WebException in the InnerException property. I want to verify the body of the response matches the string that I think should be there.
I am coming accross a problem, however, as the Response property of the WebException (which is a System.Net.SyncMemoryStream) is Disposed and can not be read.
My code:
Clubs actual;
try
{
//"201" is an invalid argument for the first parameter
actual = new Clubs(channel.GetClubs("201", "123"));
}
catch (EndpointNotFoundException e)
{
WebException w = e.InnerException as WebException;
Assert.IsNotNull(w);
HttpWebResponse resp = w.Response as HttpWebResponse;
Assert.IsNotNull(resp);
Assert.AreEqual(resp.StatusCode, HttpStatusCode.NotFound);
//Next line throws an ArgumentException saying Stream not readable
//Investigation shows it has been disposed
using (StreamReader sr = new StreamReader(resp.GetResponseStream()))
Assert.AreEqual(sr.ReadToEnd(), "League not allowed for selected club");
}
Is it normal that the properties of the InnerException are disposed? Is there any way around this?
Seems a Exception serialization issue. You might have to trap the error on server and custom build a error message
How to serialize an Exception object in C#?