Как я могу оставаться СУХОЙ с моделями просмотра asp.net mvc и атрибутами аннотации данных?

Как я могу оставаться DRY с помощью моделей представления asp.net mvc и атрибутов аннотации данных (валидация, отображение и моделирование данных) с помощью Asp.Net MVC? Я передал объектам модели, а также модели конкретных действий для просмотра. Я нахожу оба направления, чтобы иметь некоторые проблемы, пытаясь оставаться сухими.

  • Использовать объекты модели в качестве модели вашего представления:. Это прекрасно работает в простых ситуациях и позволяет только писать атрибуты аннотации данных один раз, на каждом объекте модели. Проблема возникает, когда у вас есть сложные представления, для которых требуется несколько типов объектов. Результирующая архитектура модели представления - это путаница использования классов модели представления и реальных классов моделей. Кроме того, этот метод может отображать свойства модели для вашего представления, которое вы не намерены.

  • Использовать уникальный класс модели представления для каждого действия: Класс модели представления содержит только определенные свойства вида, украшенные атрибутами аннотации данных. По моему опыту, этот метод не оказался очень сухим, поскольку атрибуты аннотации данных, как правило, дублируются в классах моделей представлений. Например, модели просмотра "Новое" и "Редактировать" разделяют много, но не все, свойств и аннотаций данных.

Как я могу оставаться DRY с моделями просмотра asp.net mvc и атрибутами аннотации данных?

Ответ 1

До сих пор я обнаружил, что использование наследования для объединения общих свойств работает лучше всего. Я использую уникальный класс представления за действие и до сих пор очень доволен решением. Он не решает 100% случаев, но он охватывает большинство и почти устраняет дубликаты атрибутов контракта.

Ответ 2

Хорошим вариантом было бы перейти от DataAnnotations к Fluent Validation. Он позволяет инкапсулировать общую логику проверки в классе, который вы можете применить позже к своим моделям.

Из документации:

[Validator(typeof(PersonValidator))]
public class Person {
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public int Age { get; set; }
}

public class PersonValidator : AbstractValidator<Person> {
    public PersonValidator() {
        RuleFor(x => x.Id).NotNull();
        RuleFor(x => x.Name).Length(0, 10);
        RuleFor(x => x.Email).EmailAddress();
        RuleFor(x => x.Age).InclusiveBetween(18, 60);
    }
}

Ответ 3

У меня есть метаданные, определенные в С# следующим образом:

public class Meta
{
    public class Client
    {
        public class Name
        {
            public const bool Required = true;
            public const DataType Type = DataType.Text;
            public const int MaxLength = 30;
            public const int MinLength = 1;
            public const string Regex = @"^[\w\d\.-_]{1,30}$";
        }

        public class Email
        {
            public const bool Required = false;
            public const DataType Type = DataType.EmailAddress;
            public const int MaxLength = 256;
            public const int MinLength = 4;
            public const string Regex = @"^[email protected]+$";
        }
    }
}

объявляя их как константы, вы можете использовать DataAnnotations как для BL-объектов, так и для моделей пользовательского интерфейса:

[DataContract]
[Serializable]
public class ClientInfo
{
    [DataMember]
    [Required(AllowEmptyStrings = !Meta.Client.Name.Required)]
    [StringLength(Meta.Client.Name.MaxLength, MinimumLength = Meta.Client.Name.MinLength)]
    [RegularExpression(Meta.Client.Name.Regex)]
    public string Name { get; set; }

    ...
}

ну да, вы дублируете атрибуты, но не метаданные! В addtition у меня есть тривиальный препроцессор для генерации sql-скриптов из шаблона (специальная обработка для *.Required и т.д.):

создать таблицу dbo.Client(   Имя nvarchar ({# Client.Name.MaxLength}) {# Client.Name.Required},   Электронная почта nvarchar ({# Client.Email.MaxLength}) {# Client.Email.Required}, ....

В пользовательском интерфейсе вы можете использовать наследование, чтобы не дублировать свойства. Например, если у вас есть модель с 10 свойствами, но вам нужно отредактировать только 2 из них, создайте EditModel и наследуйте ViewModel от него. Ключ здесь состоит в том, чтобы иметь метаданные в одном хранилище и использовать его как можно больше. Надеюсь, вы получите эту идею.