具有 IEnumerable的消息的 NServiceBus Xml 序列化问题财产

发布于 2024-09-26 05:42:30 字数 673 浏览 6 评论 0原文

我正在尝试发送带有 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 ?

预先感谢

帕特

I'm trying to send a message with an IEnumerable property, am i correct that the NServiceBus Xml serializer cannot support this ?
If i switch to using an array rather than IEnumerable it will work, if i use the binary serializer it also works

My message look like this

[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; }
}  

If the default Xml serializer cannot cater for this, is there any way to configure an alternative Xml serializer such as the BCL's DataContractSerializer ?

Thanks in advance

Pat

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

执手闯天涯 2024-10-03 05:42:30

首先,请注意,NServiceBus 中的 XML 序列化与 .NET XML 序列化不同。 .NET 变体旨在能够使用属性定制生成的 XML,以生成特定的 XML 模式,从而可能实现与其他语言的互操作性。 NServiceBus XML 序列化程序是功能的一个极小的子集,专门用于尽可能高效地在 XML 与预定义消息模式之间进行传输。

虽然 NServiceBus 序列化的结果是可读的(这在检查错误队列时非常好),但它不支持所有类型或所有格式选项。它做了它该做的事情,而且做得很好。

也就是说,IEnumerable 的问题在于它可能有很多东西。实际上,它可能只是一个数组,但也可能很容易成为一个调用数据库查询的复杂 Linq-to-SQL 表达式。为了序列化 IEnumerable,您必须将其表示为集合(列表或数组),因此您必须枚举项目。你具体什么时候会这样做?这可能会引发哪些交易问题?这就是为什么注重性能的 NServiceBus XML 序列化器不关心的原因。

NServiceBus 消息只是传递消息数据的契约。我建议只使用数组。将 IEnumerable 转换为数组(使用 ToArray() 扩展方法)并转换回来(使用 AsEnumerable() 扩展方法)非常容易,那么为什么将它作为 IEnumerable 很重要呢?

要完全回答您的问题,应该可以通过编写自己的实现 IMessageSerializer 的类并配置依赖项注入框架来使用它来交换序列化器,但我自己还没有尝试过。这将是一项艰巨的任务,因为每个端点都必须使用相同的序列化器,并且您还必须进行修改才能使用分发器、TimeoutManager、网关等。

编辑:注意到这个问题是交叉发布的NSB 组 http://tech.groups.yahoo.com/group/nservicebus /消息/8838

First, a note that XML serialization in NServiceBus is not the same thing as .NET XML Serialization. The .NET variant is all about being able to tailor the resultant XML with attributes to produce specific XML schemas, potentially for interoperability with other languages. The NServiceBus XML serializer is an extremely small subset of functionality tailored to transfer predefined message schemas to and from XML as efficiently as possible.

While the result of NServiceBus serialization is readable (which is really nice when inspecting error queues) it doesn't support all types or all formatting options. It does what it does and it does it pretty well.

That said, the problem with an IEnumerable is that it could be so many things. It could, in reality, just be an array, but it could just as easily be a complex Linq-to-SQL expression that will invoke a database query. In order to serialize the IEnumerable, you'd have to represent it as a collection (a list or array) anyway, so you have to enumerate the items. When exactly would you do that? What problems with transactions might that raise? That's why the performance-conscious NServiceBus XML serializer doesn't bother.

An NServiceBus message is just a contract to pass message data. I would suggest just using an array. It's easy enough to convert an IEnumerable to an array (with the ToArray() extension method) and back (with the AsEnumerable() extension method) so why is it important to have it as an IEnumerable?

To fully answer your question, it should be possible to swap out the serializer by writing your own class that implements IMessageSerializer and configuring the dependency injection framework to use it, but I have not tried this myself. It would be quite an undertaking, since every single endpoint would have to utilize this same serializer, and you'd also have to make modifications in order to use the Distributor, TimeoutManager, Gateway, etc.

Edit: Noticed this question was cross-posted on NSB group at http://tech.groups.yahoo.com/group/nservicebus/message/8838

等风来 2024-10-03 05:42:30

有没有办法配置替代的 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();

is there any way to configure an alternative Xml serializer such as the BCL's DataContractSerializer ?

Yes, that is certainly possible. We use the DataContractSerializer for some of our services. To get this working, you need to implement the IMessageSerialzer interface, which does the work, then register that serializer with NServiceBus during the NServiceBus.Configure method chain.

Here's the code for the message serializer. It is pretty straightforward.

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();
        }
    }
}

In order to plug this in, you could use an extension method such as the following:

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;
    }
}

This would be invoked when you configure NServiceBus like so:

NServiceBus.Configure
    // Other configuration...
    .WcfSerializer()
    // Other configuration...
    .CreateBus()
    .Start();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文