【问题标题】:MassTransit - best practices to initialize complex messagesMassTransit - 初始化复杂消息的最佳实践
【发布时间】:2020-01-28 12:52:15
【问题描述】:

假设我有一个 ASP.NET Core Web API 应用程序,我的一个操作方法接收 IEnumerable<AddressModel> addresses,其中 AddressModel 看起来像:

public class AddressModel
{
    public string Street { get; set; }
    public string ZipCode { get; set; }
    public string City { get; set; }
    public string Country { get; set; }
}

我想用它来构造一个更复杂的消息对象并通过 MassTransit 发送它 - Addresses 将是一个嵌套属性,我将设置更多字段:

public interface ICreateContact
{
    ContactTypeEnum Type { get; }
    List<IAddress> Addresses { get; }
}

public interface IAddress
{
    string Street { get; }
    string ZipCode { get; }
    string City { get; }
    string Country { get; }
}

那么,如何以最方便的可读方式创建这样的消息?我看到了一些选项,但它们都有缺点:

  1. 最直接的选择:​​i>
await _messageBus.Send<ICreateContact>(new {
    Type = ContactTypeEnum.Single,
    Addresses = addresses.Select(a => new
    {
        Street = a.Street,
        ZipCode = a.ZipCode,
        City = a.City,
        Country = a.Country
    })
});

会工作,但我不想写很多代码来分配每个属性,而且我不能使用 Automapper,因为ICreateContact/IAddress 中没有设置器。

  1. 中级:
public class CreateContact
{
    public ContactTypeEnum Type { get; set; }
    public List<Address> Addresses { get; set; }

    public class Address
    {
        public string Street { get; set; }
        public string ZipCode { get; set; }
        public string City { get; set; }
        public string Country { get; set; }
    }
}
var command = new CreateContact
{
    Type = ContactTypeEnum.Single,
    Addresses = addresses.Select(a => _mapper.Map<CreateContact.Address>(a)).ToList()
};

await _messageBus.Send<ICreateContact>(command);

看起来更好,但是如果我希望它实现ICreateContact/IAddress,那么编译器会告诉我是否错误地构造了消息?我不能这样做,因为如果我写CreateContact : ICreateContact,我的Addresses 字段必须是List&lt;IAddress&gt; 类型(即使我让Address 实现IAddress)。

总结一下我的问题:

  1. 是否可以避免中间类并使用选项 1 来自动映射属性(使用或不使用 Automapper)?
  2. 为每个服务中的消息契约创建强类型类是个好主意吗?
  3. 如果是这样 - 如何处理接口类型的嵌套属性?
  4. 如果不是 - 如果消息合约有 30 个字段,其中一个被重命名并且您需要知道哪个没有文档,该怎么办?

【问题讨论】:

标签: .net rabbitmq messaging masstransit


【解决方案1】:

首先,您不需要直接类,您可以使用另一个嵌套匿名类型来初始化地址列表。 MassTransit 的消息初始化程序按约定进行大多数类型之间的映射,包括类型转换(字符串到 int、日期等)。

由于所有属性名称都匹配,您可以轻松使用:

await _messageBus.Send<ICreateContact>(new {
    Type = ContactTypeEnum.Single,
    Addresses = addresses
});

它会使用输入addresses中的元素初始化地址列表。

第二,关于生产者的强类型类的问题?这取决于。我绝对不会在消息生产者之外分享这些具体类型。如果您想要该级别的属性类型/名称验证,您可以这样做。它只是在您的项目中管理更多的类。我已经在一些需要工程师指导级别的团队中看到了它,但更多时候我看到团队很乐意放手并在存储库级别保护合同变更。

第三,您可以使具体类型具有正确的元素类型(IAddress)并向其添加地址具体类型。这消除了数组类型问题,并且仍然允许您使用实现 IAddress 的地址具体类型。

第四,说真的,不要重命名属性!如果这是一个错误,请使用工具和 grep 全局修复它以查找跨存储库的任何用法。但是一旦它投入生产,重命名它可能会破坏事情。在这种情况下,添加一个新属性(拼写正确,无论如何)并更新生产者以最终发送两者,一旦系统全面升级,弃用原始属性。

documentation 中有更多关于 MassTransit 支持的消息初始化程序的详细信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-22
    相关资源
    最近更新 更多