Search code examples
asp.net-coreprotobuf-netgrpc-webblazor-webassemblyprotobuf-net.grpc

Exception when adding new method in a working Service using gRPC-Web and protobuf-net


I am getting the following exception:

Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: The type initializer for 'DefaultProxyCache1' threw an exception. System.TypeInitializationException: The type initializer for 'DefaultProxyCache1' threw an exception. ---> System.ArgumentException: Invalid generic arguments Parameter name: typeArguments at (wrapper managed-to-native) System.Reflection.RuntimeMethodInfo.MakeGenericMethod_impl(System.Reflection.RuntimeMethodInfo,System.Type[]) at System.Reflection.RuntimeMethodInfo.MakeGenericMethod (System.Type[] methodInstantiation) <0x342def8 + 0x000d6> in :0 at ProtoBuf.Grpc.Internal.ContractOperation.TryGetClientHelper () [0x0001b] in //src/protobuf-net.Grpc/Internal/ContractOperation.cs:291 at ProtoBuf.Grpc.Internal.ProxyEmitter.EmitFactory[TService] (ProtoBuf.Grpc.Configuration.BinderConfiguration binderConfig) [0x00477] in //src/protobuf-net.Grpc/Internal/ProxyEmitter.cs:238 at ProtoBuf.Grpc.Internal.ProxyEmitter.CreateFactory[TService] (ProtoBuf.Grpc.Configuration.BinderConfiguration binderConfig) [0x0006d] in //src/protobuf-net.Grpc/Internal/ProxyEmitter.cs:123 at ProtoBuf.Grpc.Configuration.ClientFactory+DefaultProxyCache`1[TService]..cctor () [0x00000] in //src/protobuf-net.Grpc/Configuration/ClientFactory.cs:81

My project uses gRPC-Web, Blazor web assembly and protobuf-net

This is my service contract:

[ServiceContract(Name = "Services.Customer")]
public interface ICustomerService
{       
    ValueTask<Customer> CreateCustomer(Customer customerDTO);

    ValueTask<CustomerResultSet> GetCustomers();
}

The implementation is:

public class CustomerService : ICustomerService
{
    private readonly CustomerUseCases customerLogic;

    public CustomerService(CustomerUseCases customerLogic)
    {
        this.customerLogic = customerLogic;
    }

    public async ValueTask<Customer> CreateCustomer(Customer customerDTO)
    {
        var result = await customerLogic.CreateCustomer(customerDTO);
      
        return customerDTO;
    }

    public async ValueTask<CustomerResultSet> GetCustomers()
    {
        CustomerResultSet result = new CustomerResultSet { Customers = await customerLogic.GetCustomer() };
        return result;
    }
}

As for the Datacontracts:

[DataContract]
public class CustomerResultSet
{
    [DataMember(Order = 1)]
    public IEnumerable<Customer> Customers { get; set; }
}

And,

[DataContract]
public partial class Customer
{   
    [DataMember(Order = 1)]        
    public int CustomerId { get; set; }
    [DataMember(Order = 2)]        
    public string CustomerName { get; set; }
}

Before I was returning a List of customers in the service but I realize I needed a class to model the message in order to protobuf-net be able to serialize that is why CustomerResultSet. Still, it is not working. Any help much appreciated


Solution

  • That is... odd. I can't repro it here, so I'm guessing it is something specific to Blazor. I've checked what the code does in the "regular" frameworks, and at least for me it seems to do the right things - using UnaryValueTaskAsync<Customer, Customer>() and UnaryValueTaskAsync<Empty, CustomerResultSet>(), which is what I would expect. I've improved the exception handling in that code path, to at least give us a clue what it is trying to do, so my suggestion is:

    • update to protobuf-net.Grpc version >= 1.0.119 (I'll get it deployed as soon as CI finishes)
    • retry, and let me know exactly what it says now

    Alternatively, if you have a minimal repro including the blazor bits on, say, a GitHub repo, I can happily take a look there.

    (tip: I try to keep an eye on both Stack Overflow and GitHub, but GitHub is probably more appropriate for this kind of question - I'd happily say that this is a bug, so: https://github.com/protobuf-net/protobuf-net.Grpc/issues)