Задний план
Мне нравится модель Jeffrey Palermo Onion Architecture (похожая на Гексагональная архитектура), предписывающая, чтобы Модель предметной области находилась в центре внимания, и конкретные реализации инфраструктуры, в частности Конкретные репозитории быть на периферии.
Допустим, у меня есть модель домена:
//https://libphonenumber.codeplex.com/
using libphonenumber;
namespace MyApplication.Domain
{
public class Speaker
{
public virtual string Name {get;set;}
public virtual PhoneNumber PhoneNumber {get;set;}
}
}
Теперь мне нужно показать эту модель предметной области другим командам:
- Команда пользовательского интерфейса гипотетически хочет добавить несколько атрибутов проверки данных и настраиваемых атрибутов сериализации JSON.
- Группа инфраструктуры гипотетически хочет добавить атрибуты сериализации XML и некоторые настраиваемые атрибуты из сторонней реализации базы данных.
- Команда Public API гипотетически хочет добавить атрибуты WCF.
Я не хочу давать каждой команде карт-бланш на добавление своих атрибутов в мою модель предметной области и особенно не хочу, чтобы они добавляли все свои "слои конкретные" зависимости от сборки моей модели.
И этот случай усложняется тем, что я использую сторонние «модели домена» в своих собственных (в данном случае с помощью Google LibPhoneNumber для обработки номера телефона).
В идеале каждый из них должен был бы создать свой собственный класс-оболочку, например:
using MyApplication.Domain;
namespace MyApplication.UI.DomainWrappers
{
public class UISpeaker
{
private Speaker _speaker;
public class UISpeaker(Speaker speaker = null)
{
_speaker = speaker ?? new Speaker();
}
[Required]
public virtual string Name {
get{ return _speaker.Name; }
set{ _speaker.Name = value; }
}
[Required]
public virtual PhoneNumber PhoneNumber {
get{ return _speaker.PhoneNumber ; }
set{ _speaker.PhoneNumber = value; }
}
//Conversion operators
public static implicit operator UISpeaker(Speaker s)
{
return new UISpeaker(s);
}
public static implicit operator Speaker(UISpeaker s)
{
return s._speaker;
}
}
}
Вопрос
Написание и поддержка класса UISpeaker
— это боль и скучный шаблонный код.
Есть ли лучший способ добавить атрибуты, которые каждая команда хочет добавить, не позволяя им напрямую редактировать модель предметной области? Или есть какие-то инструменты, которые могут помочь сгенерировать эти классы-оболочки (я думал, что, возможно, инструмент ткачества, такой как Fody или шаблоны T4, но я я недостаточно знаком ни с тем, ни с другим, чтобы знать, могут ли они помочь в этом случае использования).
Исследовательская работа
Я просмотрел Stackoverflow и нашел несколько похожих вопросов, но ни один из них не отвечал всем требованиям, которые я ищу:
Избегайте использования атрибута JsonIgnore в модели предметной области - Принято решение просто использовать нативные атрибуты .NET в Модели предметной области, чтобы вам не приходилось зависеть от Json.Net.
Добавить атрибут в класс другой сборки — обсуждается с использованием
CustomReflectionContext
, чтобы добавить Атрибуты существующего типа. Это выглядит очень круто, но, к сожалению, модель будет передана стороннему коду (ORM, EF, Json.Net и т. д.) для размышлений, поэтому я не думаю, что здесь это сработает.Наличие отдельной модели домена и модели сохраняемости в DDD - Подтверждено, что каждый уровень должен иметь свою собственную версию модели предметной области, но не обсуждался, существуют ли какие-либо инструменты/стратегии, облегчающие написание/поддержку этого кода.
AssociatedMetadataTypeTypeDescriptionProvider
. В некоторых слоях можно использовать классы-обертки/сопоставления и упростить задачи с помощью библиотек типаAutoMapper
. Также во всех слоях вы можете упростить задания, используя некоторые стратегии генерации кода с использованием шаблонов t4. - person Reza Aghaei   schedule 15.01.2016AssociatedMetadataTypeTypeDescriptionProvider
выглядит интересно, судя по краткой странице MSDN. Но знаете ли вы какой-нибудь пример кода, который позволит мне вводить дополнительные метаданные в класс, а затем использовать эти метаданные для стороннего кода? - person Philip Pittle   schedule 15.01.2016