Quantcast
Channel: Brian Pedersen's Sitecore and .NET Blog
Viewing all articles
Browse latest Browse all 286

Serialization and deserialization of ‘System.IntPtr’ instances are not supported. Path: $.TargetSite.MethodHandle.Value

$
0
0

I added exception handling to my .net core 6 API, and any of my error messages just throws an error 500.

The complete exception is as follows:

System.NotSupportedException: Serialization and deserialization of 'System.IntPtr' instances are not supported. Path: $.TargetSite.MethodHandle.Value.
 ---> System.NotSupportedException: Serialization and deserialization of 'System.IntPtr' instances are not supported.
   at System.Text.Json.Serialization.Converters.UnsupportedTypeConverter`1.Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
   at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer)
   at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer)
   at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer)
   at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.JsonConverter`1.WriteCore(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)

This is my controller. As you can see, it’s supposed to throw an error 400 (BadRequest):

namespace MyController
{
  [ApiController]
  [Route("api/public/v{version:apiVersion}/[controller]")]
  public class MyController : Controller
  {
    [HttpGet("{id}")]
    public async Task<IActionResult> GetData([FromRoute] int id)
    {
      try
      {
        // .. do stuff
        // .. do stuff
        // .. do stuff
      }
      catch (Exception ex)
      {
        return BadRequest(ex);
      }
    }
  }
}

But all it does is throw an error 500:

Any exception is thrown as an error 500, with the same error message.

THE PROBLEM:

It turns out, that the built in System.Text.Json serializer cannot serialize an exception. So when I return the BadRequest(ex), ex cannot be serialized to a JSON text string. And since my API is JSON based, I will get an error.

THE SOLUTION:

Do not return an exception. Instead, return an object than can be serialized, like the ProblemDetails class. I made an extension method for this purpose:

using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;
using System.Net;
using System.Security.Authentication;

namespace MyCode
{
  public static class ExceptionExtensions
  {
    public static ProblemDetails ToProblemDetails(this Exception e)
    {
      return new ProblemDetails()
      {
        Status = (int)GetErrorCode(e.InnerException ?? e),
        Title = e.Message
      };
    }

    private static HttpStatusCode GetErrorCode(Exception e)
    {
      switch (e)
      {
        case ValidationException _:
          return HttpStatusCode.BadRequest;
        case FormatException _:
          return HttpStatusCode.BadRequest;
        case AuthenticationException _:
          return HttpStatusCode.Forbidden;
        case NotImplementedException _:
          return HttpStatusCode.NotImplemented;
        default:
          return HttpStatusCode.InternalServerError;
      }
    }

  }
}

With this extension method I can easily convert the Exception to a ProblemDetails class:

namespace MyController
{
  [ApiController]
  [Route("api/public/v{version:apiVersion}/[controller]")]
  public class MyController : Controller
  {
    [HttpGet("{id}")]
    public async Task<IActionResult> GetData([FromRoute] int id)
    {
      try
      {
        // .. do stuff
        // .. do stuff
        // .. do stuff
      }
      catch (Exception ex)
      {
        return BadRequest(ex.ToProblemDetails());
      }
    }
  }
}

And whenever an error occurs, it will return the proper type and message:

Now returning a proper error 400 with a nice title

That’s it. You are now a .net core 6 API exception handling expert. Happy coding.

MORE TO READ:


Viewing all articles
Browse latest Browse all 286

Latest Images

Trending Articles



Latest Images