I have a .NET Framework 4.8 / AngularJS app that I'm trying to upgrade to .NET 6 so that I can start experimenting with newer front-end frameworks (like Blazor). The upgrade is going okay, but I consistently see this error when calling one of my API methods from the Angular JS code:
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)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ThrowNotSupportedException(WriteStack& state, NotSupportedException ex)
at System.Text.Json.Serialization.JsonConverter`1.WriteCore(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.JsonConverter`1.WriteCoreAsObject(Utf8JsonWriter writer, Object value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.JsonSerializer.WriteCore[TValue](JsonConverter jsonConverter, Utf8JsonWriter writer, TValue& value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.JsonSerializer.WriteStreamAsync[TValue](Stream utf8Json, TValue value, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)
at System.Text.Json.JsonSerializer.WriteStreamAsync[TValue](Stream utf8Json, TValue value, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)
at System.Text.Json.JsonSerializer.WriteStreamAsync[TValue](Stream utf8Json, TValue value, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|30_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
HEADERS
=======
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Authorization: Negotiate TlRMTVNTUAADAAAAGAAYAHgAAABgAWABkAAAAAAAAABYAAAADgAOAFgAAAASABIAZgAAABAAEADwAQAAFYKI4goAYUoAAAAPV7Hpy762wOgD8P0Vp4p25WsAawBvAHoAbABlAHIASwBLAE8AWgBMAEUAUgAtAEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyKkYMRt+BEmGGiFVayCimwEBAAAAAAAAsRKCqZ8i2AHdnAn8ozInsAAAAAACABAAUABSAE8ATQBPAEQARQBMAAEAEgBLAEsATwBaAEwARQBSAC0ATAAEACIAYwBvAHIAcAAuAHAAcgBvAG0AbwBkAGUAbAAuAGMAbwBtAAMANgBLAEsATwBaAEwARQBSAC0ATAAuAGMAbwByAHAALgBwAHIAbwBtAG8AZABlAGwALgBjAG8AbQAFACIAYwBvAHIAcAAuAHAAcgBvAG0AbwBkAGUAbAAuAGMAbwBtAAcACACxEoKpnyLYAQYABAACAAAACAAwADAAAAAAAAAAAQAAAAAgAABZ/aEtx5BWovcqYmfEANzjrij27KQ+UdanKJzMjBJr2QoAEAAAAAAAAAAAAAAAAAAAAAAACQAcAEgAVABUAFAALwBsAG8AYwBhAGwAaABvAHMAdAAAAAAAAAAAAKxoJoGhKPec1JQ2hdsVSsQ=
Connection: keep-alive
Content-Length: 346
Content-Type: application/json;charset=UTF-8
Cookie: ai_user=r+bRv|2022-01-12T04:50:58.222Z
Host: localhost:42721
Referer: http://localhost:42721/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="98", "Google Chrome";v="98"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Origin: http://localhost:42721
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
I'm mystified by this error. The API method looks like this:
[HttpPost]
public IActionResult Validate([FromBody] ValidationDto dto)
{
try
{
...
}
catch (Exception ex)
{
return StatusCode((int)HttpStatusCode.InternalServerError, ex.InnermostException());
}
}
The ValidationDto
class looks like this:
public class ValidationDto
{
public Guid GuidProperty { get; set; }
public DateTime? NullableDateTimeProperty { get; set; }
public int IntegerProperty { get; set; }
public ValidationType EnumProperty { get; set; }
public bool BooleanProperty { get; set; }
}
The ValidationType
enum looks like this:
public enum ValidationType
{
FirstType,
SecondType,
ThirdType,
}
The only JSON options I've specified are as follows:
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
});
Where is System.Text.Json
finding an IntPtr
that it can't deserialize?
Your code is failing during serialization not deserialization because you are catching some inner exception and trying to serialize it with System.Text.Json by returning it here:
return StatusCode((int)HttpStatusCode.InternalServerError, ex.InnermostException());
Unfortunately, System.Text.Json does not support serialization of exceptions, see System.Text.Json - can't serialize exception #43026 and also the demo fiddle https://dotnetfiddle.net/RrlPQB. It fails specifically trying to serialize TargetSite.MethodHandle.Value
which is, in fact, an IntPtr
.
If you really need to return all the exception data, you could write a custom JsonConverter<Exception>
. However, it will be easier just to return the necessary information as a string or DTO like so:
return StatusCode((int)HttpStatusCode.InternalServerError, ex.InnermostException().Message);
Or
return StatusCode((int)HttpStatusCode.InternalServerError, ex.InnermostException().ToString());
Or even an anonymous type DTO like so:
return StatusCode((int)HttpStatusCode.InternalServerError, new { ex.InnermostException().Message, StackTrace = ex.InnermostException().StackTrace?.ToString()} );
Returning exceptions as JSON messages has additional options for customizing how exceptions are returned.