无法使用 masstransit 访问 azure 服务总线队列中接口类型的值
Cannot access value of an interface type in azure service bus queue with masstransit
我正在使用 masstransit 向 azure 服务总线队列发送消息,其中消息模型接口本身有另一个接口。我的消息架构是这样的:
public interface IMyMessage
{
Guid NormalProp1 { get; set; }
IVariableProp VariableProp { get; set; }
}
public interface IVariableProp
{
}
这里IvariableProp是一个接口,因为我想在里面发送可变类型的数据。喜欢:
public class VarietyProp1 : IVariableProp
{
public Guid VarietyGuid1 { get; set; }
}
public class YetAnotherVarietyProp : IVariableProp
{
public Guid YetAnotherVarietyGuid { get; set; }
public bool YetAnotherVarietyBool { get; set; }
}
最后我的具体信息是:
public class MyConcreteMessage : IMyMessage
{
public Guid NormalProp1 { get; set; }
public IVariableProp VariableProp { get; set; }
}
我已将具体消息的实例发送到 Azure 服务总线队列。具体消息如下:
var variety1 = new MyConcreteMessage()
{
NormalProp1 = Guid.NewGuid(),
VariableProp = new VarietyProp1()
{
VarietyGuid1 = Guid.NewGuid()
}
};
此消息正在毫无问题地发送到 Azure 服务总线,并且所有值都已正确发送。 (我用 azure service bus explorer 检查过)。
当我尝试使用 masstransit 使用带有 azure 函数的消息时出现问题。在我的 Iconsumer 代码中,VariableProp 的值为 null。我的 azure 函数代码如下:
using (var dependencyScope = Program.AppDependencyResolver.BeginScope())
{
var scopedDependencyResolver = dependencyScope.Resolve<IDependencyResolver>();
IOperationContext operationContext = dependencyScope.Resolve<OperationContext>();
var serviceTriggerConfiguration = dependencyScope.Resolve<IServiceBusConsumerConfig>();
var logger = dependencyScope.Resolve<ILogger>();
logger.Info(() => $"ConsumeEventsFromQueue function is triggered");
string convertedMessage = Encoding.UTF8.GetString(message.Body, 0, message.Body.Length);
var retryCount = serviceTriggerConfiguration.RetryCount;
var interval = serviceTriggerConfiguration.IntervalInMilliSeconds;
var receiver = Bus.Factory.CreateBrokeredMessageReceiver(
binder,
cfg =>
{
cfg.CancellationToken = cancellationToken;
cfg.SetLog(traceWriter);
cfg.UseRetry(x => x.Interval(retryCount, interval));
cfg.Consumer(() => scopedDependencyResolver.Resolve<EventConsumer>());
});
await receiver.Handle(message);
我的消费者代码是:
public class EventConsumer:IConsumer<IMyMessage>
{
public async Task Consume(ConsumeContext<IMyMessage> context)
{
var message = context.Message;
}
}
在消费者代码中我无法获取 VariableProp 的值。当我设置调试指针时,它显示如下所示:
但是当我在我的函数中设置调试指针并将主体的字节数组转换为字符串时,我可以看到 VariableProp.
的值
当通过代码调用消费者时,我怀疑值是 lost/encapsulated:
cfg.Consumer(() => scopedDependencyResolver.Resolve<EventConsumer>());
我想要的是从消费者那里获取 VariableProp 的值。我能做什么?
这与其说是 MassTransit 问题,不如说是序列化问题。当您反序列化 IMyMessage
时,它会将 IVariableProp
反序列化为 IVariableProp
—— 即没有属性的接口。这是因为没有办法从接口定义中知道哪个具体类型应该隐藏在 IVariableProp
.
后面
这是一篇不错的博客post,详细说明了问题和解决方案:http://appetere.com/post/serializing-interfaces-with-jsonnet。
我个人的建议是避免这样做。使您的消息合同尽可能简单明了。我什至不确定上述解决方案是否适用于 MassTransit。如果您想走上疯狂的道路并继续使用这种方法,我将提供一条建议:可以使用单例 JsonMessageSerializer.SerializerSettings
.[=16= 配置 MassTransit JSON 序列化程序设置]
我正在使用 masstransit 向 azure 服务总线队列发送消息,其中消息模型接口本身有另一个接口。我的消息架构是这样的:
public interface IMyMessage
{
Guid NormalProp1 { get; set; }
IVariableProp VariableProp { get; set; }
}
public interface IVariableProp
{
}
这里IvariableProp是一个接口,因为我想在里面发送可变类型的数据。喜欢:
public class VarietyProp1 : IVariableProp
{
public Guid VarietyGuid1 { get; set; }
}
public class YetAnotherVarietyProp : IVariableProp
{
public Guid YetAnotherVarietyGuid { get; set; }
public bool YetAnotherVarietyBool { get; set; }
}
最后我的具体信息是:
public class MyConcreteMessage : IMyMessage
{
public Guid NormalProp1 { get; set; }
public IVariableProp VariableProp { get; set; }
}
我已将具体消息的实例发送到 Azure 服务总线队列。具体消息如下:
var variety1 = new MyConcreteMessage()
{
NormalProp1 = Guid.NewGuid(),
VariableProp = new VarietyProp1()
{
VarietyGuid1 = Guid.NewGuid()
}
};
此消息正在毫无问题地发送到 Azure 服务总线,并且所有值都已正确发送。 (我用 azure service bus explorer 检查过)。
当我尝试使用 masstransit 使用带有 azure 函数的消息时出现问题。在我的 Iconsumer 代码中,VariableProp 的值为 null。我的 azure 函数代码如下:
using (var dependencyScope = Program.AppDependencyResolver.BeginScope())
{
var scopedDependencyResolver = dependencyScope.Resolve<IDependencyResolver>();
IOperationContext operationContext = dependencyScope.Resolve<OperationContext>();
var serviceTriggerConfiguration = dependencyScope.Resolve<IServiceBusConsumerConfig>();
var logger = dependencyScope.Resolve<ILogger>();
logger.Info(() => $"ConsumeEventsFromQueue function is triggered");
string convertedMessage = Encoding.UTF8.GetString(message.Body, 0, message.Body.Length);
var retryCount = serviceTriggerConfiguration.RetryCount;
var interval = serviceTriggerConfiguration.IntervalInMilliSeconds;
var receiver = Bus.Factory.CreateBrokeredMessageReceiver(
binder,
cfg =>
{
cfg.CancellationToken = cancellationToken;
cfg.SetLog(traceWriter);
cfg.UseRetry(x => x.Interval(retryCount, interval));
cfg.Consumer(() => scopedDependencyResolver.Resolve<EventConsumer>());
});
await receiver.Handle(message);
我的消费者代码是:
public class EventConsumer:IConsumer<IMyMessage>
{
public async Task Consume(ConsumeContext<IMyMessage> context)
{
var message = context.Message;
}
}
在消费者代码中我无法获取 VariableProp 的值。当我设置调试指针时,它显示如下所示:
但是当我在我的函数中设置调试指针并将主体的字节数组转换为字符串时,我可以看到 VariableProp.
的值当通过代码调用消费者时,我怀疑值是 lost/encapsulated:
cfg.Consumer(() => scopedDependencyResolver.Resolve<EventConsumer>());
我想要的是从消费者那里获取 VariableProp 的值。我能做什么?
这与其说是 MassTransit 问题,不如说是序列化问题。当您反序列化 IMyMessage
时,它会将 IVariableProp
反序列化为 IVariableProp
—— 即没有属性的接口。这是因为没有办法从接口定义中知道哪个具体类型应该隐藏在 IVariableProp
.
这是一篇不错的博客post,详细说明了问题和解决方案:http://appetere.com/post/serializing-interfaces-with-jsonnet。
我个人的建议是避免这样做。使您的消息合同尽可能简单明了。我什至不确定上述解决方案是否适用于 MassTransit。如果您想走上疯狂的道路并继续使用这种方法,我将提供一条建议:可以使用单例 JsonMessageSerializer.SerializerSettings
.[=16= 配置 MassTransit JSON 序列化程序设置]