MassTransit - лучшие практики для инициализации сложных сообщений - PullRequest
2 голосов
/ 28 января 2020

Допустим, у меня есть 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. Самый простой вариант:
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.

нет сеттеров. Промежуточный класс:
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<IAddress> (даже если я заставлю Address реализовать IAddress).

Итак, чтобы подвести итог мои вопросы:

  1. Можно ли избежать промежуточного класса и использовать вариант 1 с автоматическим c отображением свойств (с или без Automapper)?
  2. Это хорошая идея создать строго типизированные классы для контрактов сообщений в каждом сервисе?
  3. Если так - как обращаться с вложенными свойствами типов интерфейсов?
  4. Если нет - что делать, если в контракте на сообщения имеется 30 полей, одно из них переименовано, и вам нужно знать, какие один без документации?

1 Ответ

2 голосов
/ 28 января 2020

Во-первых, вам не нужен непосредственный класс, вы можете просто использовать другой вложенный анонимный тип для инициализации списка адресов. Инициализатор сообщений MassTransit выполняет большинство сопоставлений между типами по соглашению, включая преобразования типов (строка в int, дата и т. Д. c.).

Поскольку все имена свойств совпадают, вы можете легко использовать:

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

И он будет инициализировать список адресов с элементами из входных данных адреса .

Во-вторых, ваш вопрос о строго типизированных классах для производителей? Это зависит. Я бы точно не поделился этими конкретными типами за пределами производителя сообщений. Если вам нужен этот уровень проверки типа / имени свойства, вы можете это сделать. Это просто больше классов для управления в вашем проекте. Я видел, как это было сделано в некоторых командах, которым нужен такой уровень руководства для инженеров, но чаще я вижу команды, которые рады просто позволить ему go и следить за изменениями контракта на уровне хранилища.

В-третьих, вы может заставить конкретный тип иметь правильный тип элемента (IAddress) и добавить к нему конкретные типы Address. Это устраняет проблему с типом массива и позволяет использовать конкретный тип Address, который реализует IAddress.

В-четвертых, серьезно, не переименовывайте свойства! Если это ошибка, исправьте ее глобально, используя инструмент и grep, чтобы найти какие-либо случаи использования в репозиториях. Но как только оно будет запущено в производство, его переименование может привести к поломке. В этом случае добавьте новое свойство (правильно написанное, что угодно) и обновленных производителей для отправки как в конце концов, так и после того, как системы будут обновлены по всем направлениям, не рекомендуется использовать исходное свойство.

Есть дополнительные сведения о поддержке MassTransit с инициализаторами сообщений в документации .

...