Обновление 18 декабря 2012
Поскольку этот вопрос, кажется, получает довольно много взглядов, я должен указать, что принятый ответ - это не решение, которое я использовал, но он обеспечивает ссылки и ресурсы для создания решения, но, на мой взгляд, не идеальное решение. Мой ответ содержит замены для стандартных частей структуры MVC; и вы должны использовать их только в том случае, если вам удобнее проверять, что они все еще работают для будущих версий (некоторые частные коды были вырваны из официальных источников, поскольку в базовых классах не было достаточной расширяемости).
Я могу подтвердить, однако, что эти два класса также работают для Asp.Net MVC 4, а также 3.
Также можно повторить аналогичную реализацию для платформы Web-интерфейса Asp.Net, которую я недавно сделал.
Окончательное обновление
У меня есть тип, который имеет "стандартную" проверку (требуется и т.д.), но также немного пользовательской проверки.
Некоторые из этих валидаций требуют захвата объекта службы и поиска некоторых метаданных нижнего уровня (т.е. "под уровнем модели" ) с использованием одного из других свойств в качестве ключа. Затем метаданные определяют, требуется ли одно или несколько свойств, а также допустимые форматы для этих свойств.
Чтобы быть более конкретным - тип - это объект Card Payment, упрощенный до двух из рассматриваемых свойств следующим образом:
public class CardDetails
{
public string CardTypeID { get; set; }
public string CardNumber { get; set; }
}
Затем у меня есть служба:
public interface ICardTypeService
{
ICardType GetCardType(string cardTypeID);
}
ICardType
затем содержит разные биты информации - две из которых имеют решающее значение:
public interface ICardType
{
//different cards support one or more card lengths
IEnumerable<int> CardNumberLengths { get; set; }
//e.g. - implementation of the Luhn algorithm
Func<string, bool> CardNumberVerifier { get; set; }
}
У моих контроллеров есть возможность разрешить ICardTypeService
с использованием стандартного шаблона, т.е.
var service = Resolve<ICardTypeService>();
(Хотя я должен упомянуть, что структура этого вызова является собственностью)
Что они получают за счет использования общего интерфейса
public interface IDependant
{
IDependencyResolver Resolver { get; set; }
}
Затем My framework заботится о назначении наиболее специфичного распознавателя зависимостей, доступного для экземпляра контроллера, когда он сконструирован (либо другим распознавателем, либо стандартным контроллером MVC factory). Этот метод Resolve
в последнем, но одном блоке кода является простой оболочкой вокруг этого члена Resolver
.
Итак - если я могу захватить выбранный ICardType
для платежа, полученного из браузера, я могу выполнить начальные проверки длины номера карты и т.д. Проблема заключается в том, как разрешить службу из моего переопределения IsValid(object, ValidationContext)
переопределение ValidationAttribute
?
Мне нужно пройти через текущий обработчик зависимостей контроллера в контексте проверки. Я вижу, что ValidationContext
реализует IServiceProvider
и имеет экземпляр IServiceContainer
- поэтому я должен иметь возможность создавать оболочку для моего служебного распознавателя, который также реализует один из них (возможно, IServiceProvider
).
Я уже отмечал, что во всех местах, где структура ValidationContext
создается инфраструктурой MVC, поставщик услуг всегда передается null.
Итак, в какой момент в конвейере MVC я должен искать переопределение основного поведения и внедрить моего поставщика услуг?
Я должен добавить, что это будет не единственный сценарий, в котором мне нужно сделать что-то вроде этого - так что идеально мне хотелось бы что-то, что я могу применить к конвейеру, чтобы все ValidationContext
были настроены с текущей службой провайдера для текущего контроллера.