gRPC issue with generic type and IEnumerable<T>

Something really strange happened out of a sudden and I have no idea why.
In my .net8 app, I had a response with a property of type UAOperationResult which T would ultimately be an IEnumerable.

It always worked just fine. My gRPC client was also working fine with the generated .proto file.
But out of a sudden…after the weekend…my app would not start and fail with the error message below.

It fails because the type.baseType passed is Null from the call in GrpcServiceClient RegisterSubType…GrpcConfig.Register(type.BaseType)

The only way to make it work was to change my IEnumerable to a List
I did not update my client which still has the IEnumerable and it works ok.

I am really scratching my head on why it was working just fine with IEnumerable and not anymore. Nothing obvious have changed in my code.
I have all the latest NuGet packages version installed.
The app has standard Grpc feature included.

I’d like to keep it the way it was…any idea what is going on?

2024-09-30 07:53:51.3989|ERROR|ServiceStack.ServiceStackHost|OnStartupException|System.TypeInitializationException: The type initializer for 'ServiceStack.MetaTypeConfig`1' threw an exception.
 ---> System.TypeInitializationException: The type initializer for 'ServiceStack.MetaTypeConfig`1' threw an exception.
 ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at ServiceStack.GrpcConfig.DefaultIgnoreTypes(Type type) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.GrpcClient/GrpcConfig.cs:line 95
   at ServiceStack.GrpcConfig.Register(Type type) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.GrpcClient/GrpcConfig.cs:line 115
   at ServiceStack.MetaTypeConfig`1.RegisterSubType(Type type) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.GrpcClient/GrpcServiceClient.cs:line 745
   at ServiceStack.MetaTypeConfig`1..cctor() in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.GrpcClient/GrpcServiceClient.cs:line 708
   --- End of inner exception stack trace ---
   at ServiceStack.MetaTypeConfig`1.GetMetaType() in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.GrpcClient/GrpcServiceClient.cs:line 782
   at ServiceStack.GrpcConfig.Register(Type type) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.GrpcClient/GrpcConfig.cs:line 125
   at ServiceStack.MetaTypeConfig`1..cctor() in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.GrpcClient/GrpcServiceClient.cs:line 733
   --- End of inner exception stack trace ---
   at ServiceStack.ServiceStackHost.OnStartupException(Exception ex) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack/ServiceStackHost.cs:line 1084
   at ServiceStack.ServiceStackHost.OnStartupException(Exception ex, String target, String method) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack/ServiceStackHost.cs:line 1093
   at ServiceStack.ServiceStackHost.RunPostInitPlugin(Object instance) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack/ServiceStackHost.cs:line 1360
   at System.Collections.Generic.List`1.ForEach(Action`1 action)
   at ServiceStack.ServiceStackHost.RunAfterPluginsLoaded(String specifiedContentType) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack/ServiceStackHost.cs:line 1402
   at ServiceStack.ServiceStackHost.OnAfterInit() in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack/ServiceStackHost.cs:line 1246
   at ServiceStack.ServiceStackHost.Init() in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack/ServiceStackHost.cs:line 330
   at ServiceStack.NetCoreAppHostExtensions.UseServiceStack(IApplicationBuilder app, AppHostBase appHost, Action`1 configure) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack/AppHostBase.NetCore.cs:line 754
   at Program.<Main>$(String[] args) in C:\Dev\Symasol\PG\DMO_OPC\OPC-UA-Interface\Code\OpcUaInterface\OpcUaInterface\Program.cs:line 170
   at Program.<Main>(String[] args)
message UAOperationResult_IEnumerable_UAItemValue {
   bool Success = 1;
   string Message = 2;
   repeated UAItemValue Data = 3;
   repeated UAItemValue BadData = 4;
   bool IsPartial = 5;
   repeated string Errors = 6;
}
message UAWriteResponse {
   UAOperationResult_IEnumerable_UAItemValue Result = 1;
   ResponseStatus ResponseStatus = 2;
}
[DataContract]
public class UAOperationResult<T>
{
    [DataMember(Order = 1)]
    public bool Success { get; set; }
    [DataMember(Order = 2)]
    public string Message { get; set; }
    [DataMember(Order = 3)]
    public T Data { get; set; }
    [DataMember(Order = 4)]
    public T BadData { get; set; }
    [DataMember(Order = 5)]
    public bool IsPartial { get; set; }
    [DataMember(Order = 6)]
    public List<string> Errors { get; set; }
    public UAOperationResult()
    {
        Errors = [];
    }
}
[Route("/write-multi-values", "POST")]
[DataContract]
public class UAWriteMultiValuesRequest : IReturn<UAWriteResponse>
{
    [DataMember(Order = 1)]
    public IEnumerable<UAItemValue> Values { get; set; }
}
[DataContract]
public class UAWriteResponse
{
    [DataMember(Order = 1)]   
    public UAOperationResult<IEnumerable<UAItemValue>> Result { get; set; }
    [DataMember(Order = 2)]
    public ResponseStatus ResponseStatus { get; set; }
}

The gRPC feature has not been changed for several releases so it’s unlikely to be due to a change in ServiceStack. But given DTOs shouldn’t contain interfaces, it’s recommended to always use a concrete collection like List<T> or T[] to avoid potential runtime serialization issues.

Duly noted. Thanks for again and always your quick reply.

1 Like