Skip to content

gRPC JSON transcoding google.protobuf.WellKnownTypes response/request cast error #55254

@aspmaker

Description

@aspmaker

Hello everyone. I am registering to gRPC JSON transcoding in my program.cs. And i am using in my any .proto file message-property with google.protobuf.WellKnownTypes (in example: google.protobuf.StringValue). Because i want use nullable params. When i request to the gRPC service with http/1.1, it gives me cast error in it's response.

{
    "code": 3,
    "message": "Unable to cast object of type 'Google.Protobuf.WellKnownTypes.StringValue' to type 'System.String'.",
    "details": []
}
`Grpc.AspNetCore.Grpc.JsonTranscoding.ServerCallHandler[2]
      Error when executing service method 'SayHello'.
      System.InvalidCastException: Unable to cast object of type 'Google.Protobuf.WellKnownTypes.StringValue' to type 'System.String'.
         at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.<>c__DisplayClass9_1.<SetGetter>b__1(Object obj)
         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)
         at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.SerializeAsync(Stream utf8Json, T rootValue, CancellationToken cancellationToken, Object rootValueBoxed)
         at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.SerializeAsync(Stream utf8Json, T rootValue, CancellationToken cancellationToken, Object rootValueBoxed)
         at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.SerializeAsync(Stream utf8Json, T rootValue, CancellationToken cancellationToken, Object rootValueBoxed)
         at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.SerializeAsync(Stream utf8Json, T rootValue, CancellationToken cancellationToken, Object rootValueBoxed)
         at Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal.JsonRequestHelpers.WriteResponseMessage(HttpResponse response, Encoding encoding, Object responseBody, JsonSerializerOptions options, CancellationToken cancellationToken)
         at Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal.JsonRequestHelpers.WriteResponseMessage(HttpResponse response, Encoding encoding, Object responseBody, JsonSerializerOptions options, CancellationToken cancellationToken)
         at Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal.JsonRequestHelpers.SendMessage[TResponse](JsonTranscodingServerCallContext serverCallContext, JsonSerializerOptions serializerOptions, TResponse message, CancellationToken cancellationToken)
         at Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal.JsonRequestHelpers.SendMessage[TResponse](JsonTranscodingServerCallContext serverCallContext, JsonSerializerOptions serializerOptions, TResponse message, CancellationToken cancellationToken)
         at Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal.CallHandlers.UnaryServerCallHandler`3.HandleCallAsyncCore(HttpContext httpContext, JsonTranscodingServerCallContext serverCallContext)
         at Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal.CallHandlers.ServerCallHandlerBase`3.<HandleCallAsync>g__AwaitHandleCall|14_0(JsonTranscodingServerCallContext serverCallContext, Method`2 method, Boolean isStreaming, JsonSerializerOptions serializerOptions, Task handleCall)`

Example files and codes;
.csproj file:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
	<IncludeHttpRuleProtos>true</IncludeHttpRuleProtos>
  </PropertyGroup>

  <ItemGroup>
	  <Protobuf Include="Protos\greet.proto" GrpcServices="both" ProtoRoot="Protos" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Grpc.AspNetCore" Version="2.62.0" />
    <PackageReference Include="Microsoft.AspNetCore.Grpc.JsonTranscoding" Version="9.0.0-preview.3.24172.13" />
  </ItemGroup>

</Project>

program.cs:

builder.Services
    .AddGrpc()
    .AddJsonTranscoding();

My proto file:

syntax = "proto3";

option csharp_namespace = "H.GrpcService";

import "Google/protobuf/wrappers.proto"; 
import "Google/api/annotations.proto"; 

package greet;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {
	option (google.api.http) = {
      post: "/v1/greeter",
	    body : "*"
    };
  };
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  google.protobuf.StringValue message = 1;
}

postman request json:

{
  "name": "John Doe"
}

gRPC method:

public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
    return Task.FromResult(new HelloReply
    {
        Message = new Google.Protobuf.WellKnownTypes.StringValue { Value = "H.Hello " + request.Name }
    });
}

We can only use primitive types or what is the wrong with this usage, pls can you help me. Thank you.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions