Правильная архитектура: добавление атрибутов к доменной модели в.NET

Фон

Мне нравится модель Луковой архитектуры Джеффри Палермо(похожая на шестиугольную архитектуру), которая предписывает, чтобы модель предметной области была "в центре", а конкретные реализации инфраструктуры, в частности,хранилища бетона, находились на периферии.

Скажем, у меня естьмодель предметной области:

//https://libphonenumber.codeplex.com/
using libphonenumber;

namespace MyApplication.Domain
{
    public class Speaker
    {
         public virtual string Name {get;set;}
         public virtual PhoneNumber PhoneNumber {get;set;}
    }
}

Теперь мне нужно представить этумодель предметной области другим командам:

  • Команда UI гипотетически хочет добавить несколько атрибутов проверки данных и пользовательских атрибутов сериализации JSON.
  • Команда по инфраструктуре гипотетически хочет добавить атрибуты сериализации XML и некоторые пользовательские атрибуты из сторонней реализации Базы данных.
  • Команда Public API гипотетически хочет добавить атрибуты WCF.

Я не хочу давать каждой группе карт-бланш добавить свои атрибуты в моюмодель предметной области,и я особенно не хочу, чтобы они добавляли все свои "специфичные для слоя" зависимости в мою сборку модели.

И этот случай усложняется тем, что я использую сторонние "доменные модели" самостоятельно (в данном случае для обработки номера телефона используется LibPhoneNumber от Google).

В идеале каждый из них должен был бы создать свой собственный класс-обёртку, например:

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 Templates, но я не достаточно знаком с ним, чтобы знать, могут ли они помочь в этом случае использования).

Исследование

Я осмотрел Stackru и нашел несколько похожих вопросов, но ни один из них не охватил всю область, которую я ищу:

1 ответ

Вы можете использовать эти опции для упрощения работы:

  • Метаданные Классы
  • Сопоставление объектов с объектами
  • Генерация кода

Метаданные Классы

Вы можете создавать классы метаданных и добавлять атрибуты, такие как аннотации данных и атрибуты проверки, к этим классам метаданных, а затем связывать эти классы метаданных с классами основного домена, используя AssociatedMetadataTypeTypeDescriptionProvider, Такие классы метаданных являются только контейнерами атрибутов, и использование механизмов дескрипторов типов добавляет атрибуты к вашим основным классам.

Например, вы можете таким образом зарегистрировать класс метаданных для вашей модели и позволить всем инфраструктурам, которые приносят пользу TypeDescriptor посмотрите ваши атрибуты метаданных для вашей модели:

var provider = new AssociatedMetadataTypeTypeDescriptionProvider(typeof(Model), 
                                                                 typeof(ModelMetadata));
TypeDescriptor.AddProvider(provider, typeof(Model));

Сопоставление объектов с объектами

Вы можете иметь представления моделей, бизнес-моделей и моделей доменов в разных слоях и использовать их для украшения с атрибутами, которые необходимы для каждого слоя, а затем использовать объект для сопоставления объектов, как AutoMapper упростить задачу сопоставления этих классов друг с другом.

AutoMapper - это объект-картограф. Сопоставление объектов и объектов осуществляется путем преобразования входного объекта одного типа в выходной объект другого типа. Что делает AutoMapper интересным, так это то, что он предоставляет некоторые интересные соглашения для извлечения грязной работы из выяснения того, как сопоставить тип A с типом B. Пока тип B следует установленному соглашению AutoMapper, для сопоставления двух типов требуется почти нулевая конфигурация.

Генерация кода

Вы можете упростить создание классов метаданных или просмотр классов моделей, используя некоторые инструменты генерации кода. Например, вы можете создавать классы-оболочки просто используя механизм генерации кода, такой как T4 Templates.

В Visual Studio текстовый шаблон T4 представляет собой смесь текстовых блоков и управляющей логики, которая может генерировать текстовый файл. Логика управления записывается в виде фрагментов программного кода в Visual C# или Visual Basic. Сгенерированный файл может быть текстом любого типа, например веб-страницей, файлом ресурсов или исходным кодом программы на любом языке.

Другие вопросы по тегам