1

I have a strange error with Dapper (2.0.30) on new DotNet Core 3.0.

I am trying to load data from database with this command:

await connection.QueryAsync(command)).AsList()

And I want to return result as json

return this.Ok(Database.Load("SELECT * FROM table_name;"));

But I am getting this strange error:

System.InvalidCastException: Unable to cast object of type '<GetEnumerator>d__9' to type 'System.Collections.IDictionaryEnumerator'.
   at System.Text.Json.JsonSerializer.HandleDictionary(JsonClassInfo elementClassInfo, JsonSerializerOptions options, Utf8JsonWriter writer, WriteStack& state)
   at System.Text.Json.JsonSerializer.Write(Utf8JsonWriter writer, Int32 originalWriterDepth, Int32 flushThreshold, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.JsonSerializer.WriteAsyncCore(Stream utf8Json, Object value, Type inputType, JsonSerializerOptions options, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
   at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeResultAsync>g__Logged|21_0(ResourceInvoker invoker, IActionResult result)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeResultFilters>g__Awaited|27_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

I tried exact same code on DotNet 2.0 and it worked. I guess that it has something to do with new build in json serialize, that is not compatible with dapper or something?

I looked up on internet but I could not find much (nothing actually) about this. Just this quote from this website

This looks like a bug in how we deal with types that implement IDictionary where we expect such types to return an enumerator that implements IDictionaryEnumerator (and types like DapperRow don't implement that interface).

System.Text.Json.Serialization.Tests.ValueTests.DapperTest [FAIL]
        System.InvalidCastException : Unable to cast object of type '<GetEnumerator>d__9' to type 'System.Collections.IDictionaryEnumerator'.
        Stack Trace:
          E:\GitHub\Fork\corefx\src\System.Text.Json\src\System\Text\Json\Serialization\JsonSerializer.Write.HandleDictionary.cs(64,0): at System.Text.Json.JsonSerializer.HandleDictionary(JsonClassInfo elementClassInfo, JsonSerializerOptions options, Utf8JsonWriter writer, WriteStack& state)
          E:\GitHub\Fork\corefx\src\System.Text.Json\src\System\Text\Json\Serialization\JsonSerializer.Write.cs(40,0): at System.Text.Json.JsonSerializer.Write(Utf8JsonWriter writer, Int32 originalWriterDepth, Int32 flushThreshold, JsonSerializerOptions options, WriteStack& state)
          E:\GitHub\Fork\corefx\src\System.Text.Json\src\System\Text\Json\Serialization\JsonSerializer.Write.Helpers.cs(131,0): at System.Text.Json.JsonSerializer.WriteCore(Utf8JsonWriter writer, Object value, Type type, JsonSerializerOptions options)
          E:\GitHub\Fork\corefx\src\System.Text.Json\src\System\Text\Json\Serialization\JsonSerializer.Write.Helpers.cs(107,0): at System.Text.Json.JsonSerializer.WriteCore(PooledByteBufferWriter output, Object value, Type type, JsonSerializerOptions options)
          E:\GitHub\Fork\corefx\src\System.Text.Json\src\System\Text\Json\Serialization\JsonSerializer.Write.Helpers.cs(86,0): at System.Text.Json.JsonSerializer.WriteCoreString(Object value, Type type, JsonSerializerOptions options)
          E:\GitHub\Fork\corefx\src\System.Text.Json\src\System\Text\Json\Serialization\JsonSerializer.Write.String.cs(21,0): at System.Text.Json.JsonSerializer.Serialize[TValue](TValue value, JsonSerializerOptions options)
          E:\GitHub\Fork\corefx\src\System.Text.Json\tests\Serialization\Value.WriteTests.cs(47,0): at System.Text.Json.Serialization.Tests.ValueTests.DapperTest()

Therefore, we are failing at this cast, since the enumerator that DapperRow returns is IEnumerator> and not IDictionaryEnumerator: https://github.com/dotnet/corefx/blob/b832f6ccdebd18469e4b6d03c1c9b2c9c6c14374/src/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.HandleDictionary.cs#L64

Does anyone knows how to make it work? Thanks

Update:

I kinda fix it.

First I added libary from nudget Microsoft.AspNetCore.Mvc.NewtonsoftJson. And added Newtonsoft as default json middleware.

services.AddMvc()
    .AddNewtonsoftJson();

And

services.AddControllers()
    .AddNewtonsoftJson();

But I still dont know why it did not run out of box, as it was on previous version of DotNet core.

hazzard03
  • 39
  • 1
  • 8

2 Answers2

0

As you can read in the following documentation that describes how to migrate from Asp.net core 2.2 to version 3:

The default JSON serializer for ASP.NET Core is now System.Text.Json, which is new in .NET Core 3.0. Consider using System.Text.Json when possible. It's high-performance and doesn't require an additional library dependency. However, since System.Text.Json is new, it might currently be missing features that your app needs

Maybe the new serializer doesn't support this feature yet

https://learn.microsoft.com/en-US/aspnet/core/migration/22-to-30?view=aspnetcore-3.1&tabs=visual-studio

Ezin82
  • 374
  • 1
  • 9
0

In .NET 3 the new System.Text.Json serialiser only supports dictionaries with strings as keys. If you want a dictionary with any other type you either need to write a custom deserializer or continue to use Newtonsoft JSON for now.

This is fixed in .NET 5's version: https://github.com/dotnet/runtime/pull/38056

Keith
  • 150,284
  • 78
  • 298
  • 434