1

I have the following setup for deserializing some json:

parsedResponse = JsonConvert.DeserializeObject<T>(
  json,
  new JsonSerializerSettings
  {
    Error = (object sender, ErrorEventArgs args) =>
    {
      throw new MyParseException($"Parse error: {args.ErrorContext.Error.Message}");
    },
    Converters =
    {
      new MyItemConverter(),
      new BoolConverter(),
      new UnixDateTimeConverter(),
      new NullableIntConverter(),
      new UriConverter()
    }
  }
);

In one case, json has a bunch of null values (like "title" : null, etc) which causes a NullReferenceException in one of my converters. But throwing MyParseException in the error handler causes

System.InvalidOperationException: Current error context error is different to requested error.

I think I could do this instead:

try
{
    parsedResponse = JsonConvert.DeserializeObject<T>(
      json,
      new JsonSerializerSettings
      {
        Converters =
        {
          new MyItemConverter(),
          new BoolConverter(),
          new UnixDateTimeConverter(),
          new NullableIntConverter(),
          new UriConverter()
        }
      }
    );
}
catch (Exception ex)
{
    throw new MyParseException($"Parse error: {ex.Message}");
}

But is there a better way? (Maybe something more similar to my original solution that doesn't cause the error context issue?)

Peter Csala
  • 17,736
  • 16
  • 35
  • 75
derekantrican
  • 1,891
  • 3
  • 27
  • 57
  • 1
    *Error handling lets you catch an error and choose whether to handle it and continue with serialization or let the error bubble up and be thrown in your application.* ([Source](https://www.newtonsoft.com/json/help/html/serializationerrorhandling.htm)) So basically it says that you should use this handler to set the value of `args.ErrorContext.Handled` based on your circumstances. It was not designed for your use case based on my understanding. – Peter Csala Nov 16 '21 at 08:27
  • As you can see the [`ErrorContext`'s `Error`](https://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_Serialization_ErrorContext_Error.htm) has only a getter but no setter. – Peter Csala Nov 16 '21 at 08:29
  • Unfortunately setting `args.ErrorContext.Handled = true;` and throwing the exception in the error handler still causes the "error context error is different to requested error" exception to ultimately be what is thrown. I'll see if I can poke around a bit more but the try-catch approach may be the only solution – derekantrican Nov 16 '21 at 16:25
  • Maybe my wording was not clear. The `Error` event handler is not the proper place to throw exception. – Peter Csala Nov 16 '21 at 16:46
  • If you really want to avoid using `try`-`catch` then you can make use of the [`ExceptionDispatchInfo`](https://stackoverflow.com/questions/64913559/c-rethrow-an-exception-from-a-variable-while-preserving-stack-trace/64913808) as a dirty alternative. Inside the `Error` event handler: `edi = ExceptionDispatchInfo.Capture(args.ErrorContext.Error);`. Then after the `DeserializeObject` method call you throw it like: `edi?.Throw();` – Peter Csala Nov 16 '21 at 16:49
  • 1
    Thanks for the tips (I did not know about EDI). I went with the example on the first Newtonsoft page you linked - capturing errors in a list, then I'm rethrowing as an AggregateException (if the list is not empty) after the DeserializeObject block – derekantrican Nov 16 '21 at 17:21
  • Great. Then could you please leave a post where you answer to your own question by detailing the chosen path? – Peter Csala Nov 16 '21 at 17:25

1 Answers1

0

Based on the Newtonsoft example here. I've ended up doing the following:

List<MyParseException> errors = new List<MyParseException>();

T parsedResponse = JsonConvert.DeserializeObject<T>(
  json,
  new JsonSerializerSettings
  {
    Error = (object sender, ErrorEventArgs args) =>
    {
      errors.Add(new MyParseException(String.Format("Parse error: {0}", args.ErrorContext.Error.Message), args.ErrorContext.Error));
      args.ErrorContext.Handled = true;
    },
    Converters =
    {
      new MyItemConverter(),
      new BoolConverter(),
      new UnixDateTimeConverter(),
      new NullableIntConverter(),
      new UriConverter()
    }
  }
);

if (errors.Count == 1)
{
  MyParseException firstException = errors[0];
  firstException.Data["json"] = json;
  throw firstException;
}
else if (errors.Count > 1)
{
  AggregateException ex = new AggregateException("Unable to parse json. See innner exceptions and exception.Data[\"json\"] for details", errors);
  ex.Data["json"] = json;
  throw ex;
}
Peter Csala
  • 17,736
  • 16
  • 35
  • 75
derekantrican
  • 1,891
  • 3
  • 27
  • 57