1 year ago

#318758

test-img

BLAZORLOVER

No serializer defined for type: System.Object when serializing generic API Response DTO

Context: I'm trying to improve the performance of a WebAPI endpoint that routinely returns about xx,xxx rows of data. The data is returned by a business logic pattern that tucks all API data into DTOs that look like this:

[ProtoContract]
public class ApiResponseDto {

    public ApiResponseDto() {
        Success = true;
    }

    [ProtoMember(1)]
    public bool Success { get; set; }
    
    [MaxLength(3000)]
    [ProtoMember(2)]
    public string Error { get; set; }
    
    [MaxLength(3000)]
    [ProtoMember(3)]
    public string InternalError { get; set; }

    [ProtoMember(4, DynamicType = true)]
    public object Data { get; set; }
}

Before, I was using Newtonsoft.Json to serialize this DTO, which worked well enough regardless of the Data I stuck in there.

To try protobuf-net, I've:

  1. Installed both protobuf-net and WebApiContrib.Formatting.ProtoBuf.
  2. Added config.Formatters.Insert(0, new ProtoBufFormatter()); to WebApiConfig.cs.
  3. Decorated all models with ProtoMember attributes, as demonstrated above.
  4. Updated my client app to specify headers: { Accept: 'application/x-protobuf, application/json' }

My expectation was that this would "just work", but I receive the error No serializer defined for type: System.Object. After some investigation, it looks like untyped data isn't really supported: https://github.com/protobuf-net/protobuf-net.Grpc/issues/47

I'd love to be able to enjoy an instant perf gain by dropping a few lines of code into my app, but it's looking like in order to use protocol buffers, I need to strongly type my DTOs.

To test this out, I tried creating another, typed DTO specifically for this one endpoint:

[ProtoContract]
public class SidebarApiResponseDto
{
    public SidebarApiResponseDto()
    {
        Success = true;
    }

    [ProtoMember(1)]
    public bool Success { get; set; }

    [MaxLength(3000)]
    [ProtoMember(2)]
    public string Error { get; set; }

    [MaxLength(3000)]
    [ProtoMember(3)]
    public string InternalError { get; set; }

    [ProtoMember(4)]
    public List<SidebarItem> Data { get; set; }
}

I've decorated SidebarItem's properties with the Proto attributes.

But now, the error is: {"Method not found: 'ProtoBuf.Meta.RuntimeTypeModel ProtoBuf.Meta.TypeModel.Create()'."} The only odd thing about SidebarItem is that it has a few Enums properties, otherwise it's all bools, ints, strings, List<SidebarItem>s.

Stack trace:

" at WebApiContrib.Formatting.ProtoBufFormatter.CreateTypeModel()\r\n at System.Lazy1.CreateValue()\r\n at System.Lazy1.LazyInitValue()\r\n at System.Lazy1.get_Value()\r\n at WebApiContrib.Formatting.ProtoBufFormatter.WriteToStreamAsync(Type type, Object value, Stream stream, HttpContent content, TransportContext transportContext)"

Before I get too much further along here - is there a "less obtrusive" way to upgrade a plain old webapi app from NewtonSoft.Json to protobuf-net? Perhaps by somehow allowing untyped serialization?

protobuf-net

0 Answers

Your Answer

Accepted video resources