ch-robinson / dotnet-avro

An Avro implementation for .NET
https://engineering.chrobinson.com/dotnet-avro/
MIT License
134 stars 49 forks source link

Exception serializing an anonymous object #246

Closed pedrompc closed 1 year ago

pedrompc commented 1 year ago

I am attempting to perform serialization on an anonymous object using the SerializerBuilder, so that I can produce using a byte[], however I am getting an exception.

Here's the code I'm using to serialize:

using var serializerBuilder = new SchemaRegistrySerializerBuilder(schemaRegistry);
var keySerializationContext = new SerializationContext(MessageComponentType.Key, request.TopicTarget);
var keySerializer = await serializerBuilder.Build<object>(9);
var keybytes = keySerializer.Serialize(new { Key = "key1"}, keySerializationContext);

The schema, registered under id = 9

{
  "type": "record",
  "name": "DefaultKeyEntity",
  "namespace": "Test",
  "fields": [
    {
      "name": "Key",
      "type": "string"
    }
  ]
}

I am getting the following exception:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot perform runtime binding on a null reference
   at CallSite.Target(Closure , CallSite , Object )
   at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
   at DefaultKeyEntity serializer(Closure , Object , BinaryWriter )
   at Chr.Avro.Confluent.DelegateSerializer`1.Serialize(T data, SerializationContext context)

In case this type of usage is not supported by the library, I was wondering if you had any tips on the best way to produce messages to a topic, without having a strongly typed class to start from. I basically need to serialize a dynamic object using a schema. I have tried dynamically constructing a GenericRecord from a dynamic, using the Apache.Avro library, however I have run into some limitations when trying to build nested records.

Thank you

dstelljes commented 1 year ago

Thanks for the report; this is a case that the library should support but presently does not. We’ll investigate it as a bug and provide updates here.

As a workaround, you should be able to accomplish this with dynamic objects:

dynamic key = new ExpandoObject();
key.Key = "key1";
keySerializer.Serialize(key, keySerializationContext);
pedrompc commented 1 year ago

I have tried your example, but I'm still getting the same error:

Code:

using var serializerBuilder = new SchemaRegistrySerializerBuilder(schemaRegistry);
var keySerializationContext = new SerializationContext(MessageComponentType.Key, request.TopicTarget);
var keySerializer = await serializerBuilder.Build<ExpandoObject>(9);

dynamic key = new ExpandoObject();
key.Key = "key1";
var keybytes = keySerializer.Serialize(key, keySerializationContext);

Error:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot perform runtime binding on a null reference
   at CallSite.Target(Closure , CallSite , ExpandoObject )
   at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
   at DefaultKeyEntity serializer(Closure , ExpandoObject , BinaryWriter )
   at Chr.Avro.Confluent.DelegateSerializer`1.Serialize(T data, SerializationContext context)

Either way, thank you for the help and I'll keep my eye on updates.

dstelljes commented 1 year ago

Apologies for the wait on this. The issue turned out to be two separate bugs, one in how the Schema Registry serializer was being built and another in how properties were being accessed. We'll release both fixes shortly with 9.4.1.