我正在尝试发送带有IEnumerable属性的消息,我是否认为NServiceBus Xml序列化程序不支持此功能? 如果我切换到使用数组而不是IEnumerable它将工作,如果我使用二进制序列化器它也可以工作
我的消息看起来像这样
[Serializable]
public class Parent : IMessage
{
public string Identifier { get; private set; }
public IEnumerable<Child> Children { get; private set; }
public Parent(string identifier, IEnumerable<Child> children)
{
this.Identifier = identifier;
this.Children = children;
}
}
[Serializable]
public class Child
{
public string Identifier { get; private set; }
}
如果默认的Xml序列化程序无法满足此要求,有没有办法配置替代的Xml序列化程序,如BCL的DataContractSerializer?
提前致谢
专利
答案 0 :(得分:6)
首先,请注意NServiceBus中的XML序列化与.NET XML序列化不同。 .NET变体的全部内容是能够使用属性定制结果XML以生成特定的XML模式,这可能与其他语言的互操作性。 NServiceBus XML序列化程序是一个极小的功能子集,专门用于尽可能高效地将预定义的消息模式传输到XML或从XML传输。
虽然NServiceBus序列化的结果是可读的(在检查错误队列时非常好)但它不支持所有类型或所有格式化选项。它做它做的事情并且做得很好。
那就是说,IEnumerable的问题在于它可能有很多东西。实际上,它可能只是一个数组,但它可以很容易地成为一个复杂的Linq-to-SQL表达式,它将调用数据库查询。为了序列化IEnumerable,您必须将其表示为集合(列表或数组),因此您必须枚举项目。你什么时候会这样做?交易可能带来哪些问题?这就是性能敏感的NServiceBus XML序列化程序不会打扰的原因。
NServiceBus消息只是传递消息数据的合同。我建议只使用一个数组。将IEnumerable转换为数组(使用ToArray()扩展方法)并返回(使用AsEnumerable()扩展方法)很容易,那么为什么将它作为IEnumerable进行转换很重要?
要完全回答你的问题,应该可以通过编写自己的实现IMessageSerializer的类并配置依赖注入框架来使用它来交换序列化程序,但我自己没有尝试过。这将是一项艰巨的任务,因为每个端点都必须使用相同的串行器,并且您还必须进行修改才能使用分发器,TimeoutManager,Gateway等。
编辑:注意到此问题已在http://tech.groups.yahoo.com/group/nservicebus/message/8838
的NSB小组上交叉发布答案 1 :(得分:3)
有没有办法配置替代Xml序列化程序,如BCL的DataContractSerializer?
是的,这当然是可能的。我们使用DataContractSerializer
来提供某些服务。为了实现这一点,您需要实现IMessageSerialzer
接口来完成工作,然后在NServiceBus.Configure
方法链中使用NServiceBus注册该序列化器。
这是消息序列化程序的代码。这很简单。
public class WcfMessageSerializer : IMessageSerializer
{
private readonly IList<Type> knownTypes = new List<Type>();
public IList<Type> MessageTypes
{
get { return knownTypes; }
set
{
knownTypes.Clear();
foreach (var type in value)
{
if (!type.IsInterface && typeof(IMessage).IsAssignableFrom(type)
&& !knownTypes.Contains(type))
{
knownTypes.Add(type);
}
}
}
}
public void Serialize(IMessage[] messages, Stream stream)
{
var xws = new XmlWriterSettings
{
ConformanceLevel = ConformanceLevel.Fragment
};
using (var xmlWriter = XmlWriter.Create(stream, xws))
{
var dcs = new DataContractSerializer(typeof(IMessage), knownTypes);
foreach (var message in messages)
{
dcs.WriteObject(xmlWriter, message);
}
}
}
public IMessage[] Deserialize(Stream stream)
{
var xrs = new XmlReaderSettings
{
ConformanceLevel = ConformanceLevel.Fragment
};
using (var xmlReader = XmlReader.Create(stream, xrs))
{
var dcs = new DataContractSerializer(typeof(IMessage), knownTypes);
var messages = new List<IMessage>();
while (false == xmlReader.EOF)
{
var message = (IMessage)dcs.ReadObject(xmlReader);
messages.Add(message);
}
return messages.ToArray();
}
}
}
为了将其插入,您可以使用扩展方法,如下所示:
public static class ConfigureWcfSerializer
{
public static Configure WcfSerializer(this Configure config)
{
var messageTypes = Configure.TypesToScan
.Where(t => typeof(IMessage).IsAssignableFrom(t))
.ToList();
config.Configurer
.ConfigureComponent<WcfMessageSerializer>(ComponentCallModelEnum.Singleton)
.ConfigureProperty(ms => ms.MessageTypes, messageTypes);
return config;
}
}
当你配置NServiceBus时会调用它:
NServiceBus.Configure
// Other configuration...
.WcfSerializer()
// Other configuration...
.CreateBus()
.Start();