Контекстная проверка Entity Framework - PullRequest
2 голосов
/ 20 сентября 2010

Как бы вы реализовали валидацию для сущностей каркаса сущностей, когда в определенных ситуациях должна применяться другая логика валидации?

Например, проверить сущность одним способом, если пользователь является администратором, в противном случае проверить другим способом.

Ответы [ 3 ]

2 голосов
/ 20 сентября 2010

Я добавляю атрибуты проверки в контекстно-зависимые, выделенные модели редактирования.

Сущность имеет только проверки, которые применяются к всем сущностям.

2 голосов
/ 20 сентября 2010

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

Это похоже на хорошую работу для блока приложения проверки библиотеки предприятия (VAB), поскольку она позволяет проверять эти сложные сценарии.Если вы хотите сделать это, забудьте проверку на основе атрибутов;это просто не сработает.Для этого вам потребуется проверка на основе конфигурации.

Что вы можете сделать с помощью VAB, это использовать файл конфигурации, который содержит фактическую проверку.Это немного зависит от того, какими должны быть действительные правила валидации, но вы можете создать базовую конфигурацию, которая всегда сохраняется для каждого объекта в вашем домене.А затем создайте одну или несколько конфигураций, которые содержат только расширенных проверок.Скажем, например, что у вас есть файл validation_base.config, файл validation_manager.config и validation_admin.config.

Что вы можете сделать, это объединить эти проверки вместе в зависимости от роли пользователя.Посмотрите, например, на этот пример, который создает три источника конфигурации на основе файла конфигурации:

var base = new FileConfigurationSource("validation_base.config");
var mngr = new FileConfigurationSource("validation_manager.config");
var admn = new FileConfigurationSource("validation_admin.config");

Теперь вам нужно объединить эти файлы в (как минимум) две конфигурации.Один содержит базу + менеджер, а другой содержит правила база + администратор.Хотя слияние не является чем-то, что поддерживается из коробки, эта статья покажет вам, как это сделать.Используя код из этой статьи, вы сможете сделать следующее:

var managerValidations = 
    new ValidationConfigurationSourceCombiner(base, mngr);

var adminValidations =
    new ValidationConfigurationSourceCombiner(base, admn);

Последнее, что вам нужно сделать, это обернуть эти проверки в класс, который возвращает правильный набор, основанный на ролиПользователь.Вы можете сделать это следующим образом:

public class RoleConfigurationSource : IConfigurationSource
{
    private IConfigurationSource base;
    private IConfigurationSource managerValidations;
    private IConfigurationSource adminValidations;

    public RoleConfigurationSource()
    {
        this.base = new FileConfigurationSource("validation_base.config");
        var mngr = new FileConfigurationSource("validation_manager.config");
        var admn = new FileConfigurationSource("validation_admin.config");

        managerValidations = 
            new ValidationConfigurationSourceCombiner(base, mngr);

        adminValidations =
            new ValidationConfigurationSourceCombiner(base, admn);
    }

    public ConfigurationSection GetSection(string sectionName)
    {
        if (sectionName == ValidationSettings.SectionName)
        {
            if (Roles.UserIsInRole("admin"))
            {
                return this.adminValidations;
            }
            else
            {
                return this.managerValidations;
            }
        }

        return null;
    }

    #region IConfigurationSource Members

    // Rest of the IConfigurationSource members left out.
    // Just implement them by throwing an exception from
    // their bodies; they are not used.

    #endregion
}

Теперь этот RoleConfigurationSource можно создать один раз, и вы можете предоставить его при проверке ваших объектов следующим образом:

static readonly IConfigurationSource validationConfiguration =
    new RoleConfigurationSource();

Validator customerValidator =
    ValidationFactory.CreateValidator<Customer>(validationConfiguration);

ValidationResults results = customerValidator.Validate(customer);

if (!results.IsValid)
{
    throw new InvalidOperationException(results[0].Message);
}

Обратите внимание, чтоблок приложения проверки не является простой структурой.Это займет некоторое время, чтобы выучить это.Когда ваше приложение достаточно велико, ваши конкретные требования, тем не менее, оправдывают его использование.Если вы выбираете VAB, начните с чтения документа « Hands-On Labs ».Если у вас возникли проблемы, возвращайтесь сюда в SO; -)

Удачи.

1 голос
/ 20 сентября 2010

Пока я не услышу более яркую идею, я делаю это:

public partial class MyObjectContext
{
    ValidationContext ValidationContext { get; set; }

    partial void OnContextCreated()
    {
        SavingChanges += new EventHandler(EntitySavingChanges);
    }

    private void EntitySavingChanges(object sender, EventArgs e)
    {
        ObjectStateManager
            .GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Deleted)
            .Where(entry => entry.Entity is IValidatable).ToList().ForEach(entry =>
            {
                var entity = entry.Entity as IValidatable;
                entity.Validate(entry, ValidationContext);
            });
    }
}

interface IValidatable
{
    void Validate(ObjectStateEntry entry, ValidationContext context);
}

public enum ValidationContext
{
    Admin,
    SomeOtherContext
}

public partial class MyEntity : IValidatable
{
    public ValidationContext ValidationContext { get; set; }

    public void Validate(ObjectStateEntry entry, ValidationContext context)
    {
        // this validation doesn't apply to admins
        if (context != ValidationContext.Admin)
        {
            // validation logic here
        }
    }  
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...