aspnetcore icon indicating copy to clipboard operation
aspnetcore copied to clipboard

gRPC JSON transcoding — Unable to resolve descriptor for Enum (deserialize enum from string value)

Open AndrewP-GH opened this issue 3 years ago • 1 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Describe the bug

It's impossible to deserialize a string value of protobuf enum using Microsoft.AspNetCore.Grpc.JsonTranscoding 7.0.0. Received rror:

{
  "code": 3,
  "message": "Unable to resolve descriptor for Example.Country.Alpha3CountryCode.",
  "details": []
}

I think the problem with the method ResolveEnumDescriptor in Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal.Json.EnumConverter<TEnum>. It expects that the enum type is defined as a nested type in a message

private static EnumDescriptor? ResolveEnumDescriptor(Type typeToConvert)
{
    var containingType = typeToConvert?.DeclaringType?.DeclaringType;

    if (containingType != null)
    {
        var messageDescriptor = JsonConverterHelper.GetMessageDescriptor(containingType);
        if (messageDescriptor != null)
        {
            for (var i = 0; i < messageDescriptor.EnumTypes.Count; i++)
            {
                if (messageDescriptor.EnumTypes[i].ClrType == typeToConvert)
                {
                    return messageDescriptor.EnumTypes[i];
                }
            }
        }
    }

    return null;
}

Setting TypeRegistry in the transcoding options doesn't solve this problem.

Expected Behavior

Both int value and string value can be deserialized from JSON.

Steps To Reproduce

I wrote a small web app to reproduce this issue. Link.

Exceptions (if any)

      System.InvalidOperationException: Unable to resolve descriptor for Example.Country.Alpha3CountryCode.
         at Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal.Json.EnumConverter`1.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
         at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
         at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
         at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
         at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
         at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
         at System.Text.Json.Serialization.JsonConverter`1.ReadCoreAsObject(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
         at System.Text.Json.JsonSerializer.ReadCore[TValue](Utf8JsonReader& reader, JsonTypeInfo jsonTypeInfo, ReadStack& state)
         at System.Text.Json.JsonSerializer.ContinueDeserialize[TValue](ReadBufferState& bufferState, JsonReaderState& jsonReaderState, ReadStack& readStack, JsonTypeInfo jsonTypeInfo)
         at System.Text.Json.JsonSerializer.ReadFromStreamAsync[TValue](Stream utf8Json, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)
         at Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal.JsonRequestHelpers.ReadMessage[TRequest](JsonTranscodingServerCallContext serverCallContext, JsonSerializerOptions serializerOptions)
         at Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal.JsonRequestHelpers.ReadMessage[TRequest](JsonTranscodingServerCallContext serverCallContext, JsonSerializerOptions serializerOptions)
info: Grpc.AspNetCore.Grpc.JsonTranscoding.ServerCallHandler[3]
      Error status code 'InvalidArgument' with detail 'Unable to resolve descriptor for Example.Country.Alpha3CountryCode.' raised.
      System.InvalidOperationException: Unable to resolve descriptor for Example.Country.Alpha3CountryCode.
         at Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal.Json.EnumConverter`1.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
         at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
         at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
         at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
         at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
         at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
         at System.Text.Json.Serialization.JsonConverter`1.ReadCoreAsObject(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
         at System.Text.Json.JsonSerializer.ReadCore[TValue](Utf8JsonReader& reader, JsonTypeInfo jsonTypeInfo, ReadStack& state)
         at System.Text.Json.JsonSerializer.ContinueDeserialize[TValue](ReadBufferState& bufferState, JsonReaderState& jsonReaderState, ReadStack& readStack, JsonTypeInfo jsonTypeInfo)
         at System.Text.Json.JsonSerializer.ReadFromStreamAsync[TValue](Stream utf8Json, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken)
         at Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal.JsonRequestHelpers.ReadMessage[TRequest](JsonTranscodingServerCallContext serverCallContext, JsonSerializerOptions serializerOptions)
         at Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal.JsonRequestHelpers.ReadMessage[TRequest](JsonTranscodingServerCallContext serverCallContext, JsonSerializerOptions serializerOptions)

.NET Version

7.0.100

Anything else?

Packages:

<PackageReference Include="Grpc.AspNetCore" Version="2.50.0" />
<PackageReference Include="Grpc.AspNetCore.Server.Reflection" Version="2.50.0" />
<PackageReference Include="Microsoft.AspNetCore.Grpc.JsonTranscoding" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Grpc.Swagger" Version="0.3.0" />

AndrewP-GH avatar Nov 24 '22 19:11 AndrewP-GH

Hi, I took a look at this and non-nested enum values don't work in .NET 7. Unfortunately, there is no way to work around this without changing your proto file. You have to make the enum nested inside a message.

I have a PR to fix this - https://github.com/dotnet/aspnetcore/pull/45273. I will get it backported to .NET 7 so a future service release of .NET 7 gets the fix.

JamesNK avatar Nov 25 '22 02:11 JamesNK

Cool! When is this update going to be released?

AndrewP-GH avatar Nov 28 '22 07:11 AndrewP-GH

It might take a couple of months before it makes it onto NuGet.org in an update.

JamesNK avatar Nov 28 '22 08:11 JamesNK

@AndrewP-GH Attached is an unofficial package from the fix PR. It's one option if you don't want to wait.

Microsoft.AspNetCore.Grpc.JsonTranscoding.7.0.2.zip

JamesNK avatar Dec 02 '22 05:12 JamesNK

Thank you!

AndrewP-GH avatar Dec 02 '22 10:12 AndrewP-GH