Допустим, у меня есть 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; }
}
Итак, как создать такое сообщение наиболее удобным для чтения способом? Я вижу несколько вариантов, но все они имеют недостатки:
- Самый простой вариант:
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 с автоматическим c отображением свойств (с или без Automapper)?
- Это хорошая идея создать строго типизированные классы для контрактов сообщений в каждом сервисе?
- Если так - как обращаться с вложенными свойствами типов интерфейсов?
- Если нет - что делать, если в контракте на сообщения имеется 30 полей, одно из них переименовано, и вам нужно знать, какие один без документации?