C#融合卡夫卡问题与avro序列化

C#融合卡夫卡问题与avro序列化,c#,apache-kafka,avro,confluent-platform,C#,Apache Kafka,Avro,Confluent Platform,我正在使用docker从中运行kafka和其他服务 在我的测试项目中使用了kafka、avro和schemaRegistry的合流nuget包 如果要发送json消息,我到目前为止没有问题,但我正在努力发送avro序列化消息 我看到了一个例子,我试着用同样的方法来做,但最终我得到了一个异常,如下所示: 本地:值序列化错误 在Confluent.Kafka.Producer中,在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSucce

我正在使用docker从中运行kafka和其他服务 在我的测试项目中使用了kafka、avro和schemaRegistry的合流nuget包

如果要发送json消息,我到目前为止没有问题,但我正在努力发送avro序列化消息

我看到了一个例子,我试着用同样的方法来做,但最终我得到了一个异常,如下所示:

本地:值序列化错误
在Confluent.Kafka.Producer中,在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务任务)中,在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务任务)中,在System.Runtime.CompilerServices.TaskAwaiter中 在Kafka_producer.KafkaService.d_10.MoveNext()中 C:\Users\lu95eb\source\repos\Kafka\u playerdy\Kafka producer\KafkaService.cs:第126行

内部例外

对象引用未设置为对象的实例。
在Confluent.SchemaRegistry.Serdes.SpecificSerializerImpl
1..ctor(ISchemaRegistryClient SchemaRegistrClient,Boolean autoRegisterSchema,Int32 initialBufferSize)处,在Confluent.SchemaRegistry.Serdes.AvroSerializer处
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)
在System.Runtime.CompilerServices.TaskWaiter.HandleNonSuccessAndDebuggerNotification(任务任务)中
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(任务任务)
在Confluent.Kafka.Producer`2.d_u52.MoveNext()

这是我的录音课

public class UserInfo : ISpecificRecord
{
    public string Name { get; set; }
    public int[] Numbers { get; set; }

    public Schema Schema => Schema.Parse(@"
        {
          ""name"": ""UserInfo"",
          ""type"": ""record"",
          ""namespace"": ""kafka"",
          ""fields"": [
            {
              ""name"": ""Name"",
              ""type"": ""string""
            },
            {
              ""name"": ""Numbers"",
              ""type"": {
                ""type"": ""array"",
                ""items"": ""int""
              }
            }
          ]
        }
        ");

    public object Get(int fieldPos)
    {
        switch (fieldPos)
        {
            case 0: return Name;
            case 1: return Numbers;
            default: throw new AvroRuntimeException($"Bad index {fieldPos} in Get()");
        }
    }

    public void Put(int fieldPos, object fieldValue)
    {
        switch (fieldPos)
        {
            case 0: Name = (string)fieldValue; break;
            case 1: Numbers = (int[])fieldValue; break;
            default: throw new AvroRuntimeException($"Bad index {fieldPos} in Put()");
        }
    }
}
以及用于发送消息的方法

private async Task SendSpecificRecord(UserInfo userInfo)
    {
        using (var schemaRegistry = new CachedSchemaRegistryClient(new SchemaRegistryConfig { Url = _schemaRegistryUrl }))
        using (var producer =
            new ProducerBuilder<string, UserInfo>(new ProducerConfig { BootstrapServers = _brokerUrl })
                .SetKeySerializer(new AvroSerializer<string>(schemaRegistry))
                .SetValueSerializer(new AvroSerializer<UserInfo>(schemaRegistry))
                .Build())
        {

            var message = new Message<string, UserInfo>
            {
                Key = userInfo.Name,
                Value = userInfo
            };


            await producer.ProduceAsync(SpecificTopic, message);
        }
    }
专用异步任务SendSpecificRecord(UserInfo UserInfo)
{
使用(var schemaRegistry=new CachedSchemaRegistryClient(new SchemaRegistryConfig{Url=\u schemaRegistryUrl}))
使用(var)生成器=
新建ProducerBuilder(新建ProducerConfig{bootstrapserver=\u brokerUrl})
.SetKeySerializer(新的AvroSerializer(schemaRegistry))
.SetValueSerializer(新的AvroSerializer(schemaRegistry))
.Build())
{
var消息=新消息
{
Key=userInfo.Name,
Value=userInfo
};
wait producer.ProduceAsync(特定主题、消息);
}
}
KafkaService.cs:126行是
wait producer.ProduceAsync(specificttopic,message)

就像我在一开始写的那样,我对schemaRegistry没有任何问题——我注册了模式,它们可以正确地用于json,我对主题、代理、消费者或其他方面没有问题

如果有人能指出我做错了什么,我将不胜感激。
提前谢谢。

如果有人对解决方案感到好奇(我无法想象有人会是什么样子;) 然后我编写了“定制”avro序列化程序和反序列化程序,工作起来很有魅力

public class CustomAvroSerializer<T> : IAsyncSerializer<T>
    where T : class, ISpecificRecord
{
    public Task<byte[]> SerializeAsync(T data, SerializationContext context)
    {
        return Task.Run(() =>
        {
            using (var ms = new MemoryStream())
            {
                var enc = new BinaryEncoder(ms);
                var writer = new SpecificDefaultWriter(data.Schema);
                writer.Write(data, enc);
                return ms.ToArray();
            }
        });
    }
}

public class CustomAvroDeserializer<T> : IDeserializer<T>
    where T : class, ISpecificRecord
{
    public T Deserialize(ReadOnlySpan<byte> data, bool isNull, SerializationContext context)
    {
        using (var ms = new MemoryStream(data.ToArray()))
        {
            var dec = new BinaryDecoder(ms);
            var regenObj = (T)Activator.CreateInstance(typeof(T));

            var reader = new SpecificDefaultReader(regenObj.Schema, regenObj.Schema);
            reader.Read(regenObj, dec);
            return regenObj;
        }
    }
}
公共类CustomAvroSerializer:IAsyncSerializer
其中T:class,IsSpecificRecord
{
公共任务SerializeAsync(T数据,SerializationContext上下文)
{
返回任务。运行(()=>
{
使用(var ms=new MemoryStream())
{
var enc=新的二进制编码器(ms);
var writer=新的SpecificDefaultWriter(data.Schema);
writer.Write(数据,enc);
返回ToArray女士();
}
});
}
}
公共类CustomAvroDeserializer:IDeserializer
其中T:class,IsSpecificRecord
{
public T反序列化(ReadOnlySpan数据,bool为null,SerializationContext)
{
使用(var ms=new MemoryStream(data.ToArray()))
{
var dec=新的二进制解码器(ms);
var regenObj=(T)Activator.CreateInstance(typeof(T));
var reader=新的SpecificDefaultReader(regenObj.Schema,regenObj.Schema);
reader.Read(regenObj,dec);
返回regenObj;
}
}
}

如果有人对解决方案感到好奇(我无法想象有人会是什么样子;) 然后我编写了“定制”avro序列化程序和反序列化程序,工作起来很有魅力

public class CustomAvroSerializer<T> : IAsyncSerializer<T>
    where T : class, ISpecificRecord
{
    public Task<byte[]> SerializeAsync(T data, SerializationContext context)
    {
        return Task.Run(() =>
        {
            using (var ms = new MemoryStream())
            {
                var enc = new BinaryEncoder(ms);
                var writer = new SpecificDefaultWriter(data.Schema);
                writer.Write(data, enc);
                return ms.ToArray();
            }
        });
    }
}

public class CustomAvroDeserializer<T> : IDeserializer<T>
    where T : class, ISpecificRecord
{
    public T Deserialize(ReadOnlySpan<byte> data, bool isNull, SerializationContext context)
    {
        using (var ms = new MemoryStream(data.ToArray()))
        {
            var dec = new BinaryDecoder(ms);
            var regenObj = (T)Activator.CreateInstance(typeof(T));

            var reader = new SpecificDefaultReader(regenObj.Schema, regenObj.Schema);
            reader.Read(regenObj, dec);
            return regenObj;
        }
    }
}
公共类CustomAvroSerializer:IAsyncSerializer
其中T:class,IsSpecificRecord
{
公共任务SerializeAsync(T数据,SerializationContext上下文)
{
返回任务。运行(()=>
{
使用(var ms=new MemoryStream())
{
var enc=新的二进制编码器(ms);
var writer=新的SpecificDefaultWriter(data.Schema);
writer.Write(数据,enc);
返回ToArray女士();
}
});
}
}
公共类CustomAvroDeserializer:IDeserializer
其中T:class,IsSpecificRecord
{
public T反序列化(ReadOnlySpan数据,bool为null,SerializationContext)
{
使用(var ms=new MemoryStream(data.ToArray()))
{
var dec=新的二进制解码器(ms);
var regenObj=(T)Activator.CreateInstance(typeof(T));
var reader=新的SpecificDefaultReader(regenObj.Schema,regenObj.Schema);
reader.Read(regenObj,dec);
返回regenObj;
}
}
}

我面临同样的问题,在查看github上的库代码后,我能够解决它。 似乎schema registry在实现isSpecificRecord的类中需要一个名为_schema的静态字段

所以如果你加一个 公共静态_SCHEMA=SCHEMA.Parse(

并更改公共模式=>UserInfo.\u模式


如果没有您的变通方法,它也能正常工作,因为您的变通方法只会忽略模式注册表。

我也遇到了同样的问题,并且在查看github上的库代码后能够解决它。 似乎schema registry在实现isSpecificRecord的类中需要一个名为_schema的静态字段

所以如果你加一个 公共静态_SCHEMA=SCHEMA.Parse(

并更改公共模式=>UserInfo.\u模式

它将在没有您的变通方法的情况下工作,您的变通方法只会忽略模式注册表