Как вводить зависимости, используемые для проверки в .NET MVC3?
У нас есть довольно много методов проверки, которым необходимо получить доступ к репозиториям/базе данных для выполнения своей работы. До сих пор мы использовали шаблон локатора службы (хотя и экономно), чтобы выполнить это в пользовательских ValidationAttributes:
public override bool IsValid(object value)
{
// use custom service locator in our app infrastructure
var repos = DependencyInjector.Current.GetService<IXyzRepository>();
...
}
Я знаю, что это:( как анти-шаблон, и мы хотели бы использовать более правильный подход. Мы используем единство, и я читаю этот пост, который говорит, что нужно использовать метод наращивания. Однако ссылка в принятом ответе говорит, что документация устарела (отставной контент).
В решении нет необходимости использовать атрибут проверки, я полагаю, что он мог бы использовать документ IValidatableObject, однако проблема остается: как ввести зависимость в модель. Нужно ли нам для этого использовать специализированное связующее?
Другим решением было бы выполнить проверку в контроллере, где инъекция зависимостей проста. Для меня это чувствует себя загроможденным. Я бы хотел, чтобы модель была подтверждена к моменту ее получения.
Также мы иногда используем [RemoteAttribute] для выполнения некоторых из этих проверок на клиенте. В настоящее время эти методы создают модель представления и делегируют валидацию модели, используя статический метод Validator.TryValidateObject.
Как вы выполнили проверку, которая требует, чтобы вложенная зависимость выполняла свою работу без использования анти-шаблона SL?
Ответы
Ответ 1
Как вы выполнили проверку, требующую ввода чтобы выполнить свою работу без использования анти-шаблона SL?
Я использую FluentValidation.NET для выполнения проверки в моих приложениях. Это позволяет мне вставлять зависимости в мои валидаторы. У этого есть действительно хорошая интеграция с ASP.NET MVC. Он также поддерживает автоматическую проверку на стороне клиента для стандартных правил точно так же, как аннотации данных с использованием jquery unobtrusive validate:
- NotNull/NotEmpty
- Матчи (регулярное выражение)
- InclusiveBetween (диапазон)
- CreditCard
- Email
- EqualTo (сравнение сравнений между свойствами)
- Длина
Я никогда не использовал аннотации данных для выполнения проверки. Они абсолютно бесполезны, когда вам нужно обрабатывать несколько более сложных сценариев проверки, когда вам нужно проверить зависимые свойства и даже использовать некоторую услугу. В предыдущем предложении я выделил курсив курсивом, потому что, я не думаю, что проверка того, что одно из двух свойств требуется, является действительно сложным сценарием валидации, и все же просто проверьте количество инфраструктуры, которую вы должны написать, чтобы реализовать ее, используя аннотации данных. Глядя на этот код, вы уже не знаете, что вы проверяете.
Ответ 2
Внесите свою валидацию в свою модель.
Атрибуты проверки могут стать неудобными для работы, когда ваши истории проверки становятся более сложными. Тьфу!
Мне нравится использовать Entity Framework с кодом First. В этот момент я полностью контролирую свою модель. Я также использую FluentValidation, например @Darin Dimitrov, и мне очень нравится его простота использования и простой синтаксис.
Вот как вы собрали это.
Я предполагаю, что у вас есть сборка с вашими интерфейсами или контрактами.
Это будет базовый интерфейс для ваших моделей...
using System.ComponentModel;
using FluentValidation.Results;
public interface IAbstractBase : IDataErrorInfo
{
bool IsValid { get; }
ValidationResult SelfValidate();
}
и его коллега в вашем бизнес-слое выглядит следующим образом:
using System;
using System.Linq;
using FluentValidation.Results;
using Contracts;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
public abstract class AbstractBase : IAbstractBase
{
#region IDataErrorInfo
public abstract ValidationResult SelfValidate();
[NotMapped]
public bool IsValid
{
get
{
return SelfValidate().IsValid;
}
}
[NotMapped]
public string Error
{
get
{
var results = SelfValidate().Errors.Select(s => string.Format("● {0}{1}", s.ErrorMessage, Environment.NewLine)).ToArray();
return string.Join("", results);
}
}
[NotMapped]
public IList<ValidationFailure> Errors
{
get
{
var results = SelfValidate().Errors;
return results;
}
}
[NotMapped]
public string this[string columnName]
{
get
{
var validationResults = SelfValidate();
if (validationResults == null) return string.Empty;
var columnResults = validationResults.Errors.FirstOrDefault(x => string.Compare(x.PropertyName, columnName, true) == 0);
return columnResults != null ? columnResults.ErrorMessage : string.Empty;
}
}
#endregion
}
Это ваш базовый класс для ваших моделей. Убедитесь, что вы применяете абстрактный метод в своих моделях. Это должно выглядеть так.
public class MyModel : AbstractBase, IMyModel
{
private AbstractValidator<IMyModelValidator> _myModelValidator;
public MyModel():this(new MyModelValidator()){};
public MyModel(AbstractValidator<IMyModelValidator> myModelValidator){
_myModelValidator = myModelValidator;
};
public int MyModelId { get; set; }
public string Name { get; set; }
public DateTime CreatedDate { get; set; }
public override ValidationResult SelfValidate()
{
return _myModelValidator.Validate(this);
}
}
Ваш класс проверки будет выглядеть примерно так.
public class MyModelValidator : AbstractValidator<IMyModelValidator>
{
private IMyModelProvider _myModelProvider;
public MyModelValidator(IMyModelProvider myModelProvider){ _myModelProvider = myModelProvider;};
private void SetRules()
{
RuleFor(x => x.Name).NotEmpty().WithMessage("Please specify a project name.");
RuleFor(x => x.Name.Length).LessThanOrEqualTo(100).WithMessage("The project name must be less than or equal to 100 characters.");
}
public override ValidationResult Validate(IMyModel instance)
{
SetRules();
return base.Validate(instance);
}
}
Передайте результаты проверки вашей модели в свое представление в своем контроллере, используя следующий вызов в вашем контроллере.
TryValidateModel(your model here);
После вызова этого в контроллере вызовите свойство model.IsValid.
Удостоверьтесь, что вы регистрируете все, и вам должно быть хорошо идти. Я предполагаю, что вы можете заполнить недостающие части.
Общая картина выглядит так:
![enter image description here]()