Обновление 18 декабря 2012 г.
Поскольку этот вопрос, похоже, получает довольно много просмотров, я должен указать, что принятый ответ - это не то решение, которое я использовал, но он предоставляет ссылки и ресурсы для создания решения, но, на мой взгляд, не идеальное решение. Мой ответ содержит замен для стандартных частей инфраструктуры MVC; и вы должны использовать их только в том случае, если вам удобно проверять, что они все еще работают для будущих версий (некоторый частный код был извлечен из официальных источников, поскольку в базовых классах не было достаточной расширяемости).
Однако я могу подтвердить, что эти два класса также работают для Asp.Net MVC 4, а также для 3.
Также можно повторить подобное реализация для платформы Asp.Net Web API, которую я сделал недавно.
Конец обновления
У меня есть тип, который имеет много «стандартной» проверки (требуется и т. д.), но также немного настраиваемой проверки
Некоторые из этих проверок требуют захвата служебного объекта и поиска некоторых метаданных более низкого уровня (то есть «ниже» уровня модели), используя одно из других свойств в качестве ключа. Затем метаданные определяют, требуется ли одно или несколько свойств, а также допустимые форматы для этих свойств.
Чтобы быть более конкретным, типом является объект платежа по карте, упрощен до двух из рассматриваемых свойств следующим образом:
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). Этот метод Resolve
в предпоследнем блоке кода является простой оболочкой вокруг этого члена Resolver
.
Итак - если я смогу получить выбранный ICardType
для платежа, полученного от браузера, я смогу выполнить начальную проверку длины номера карты и т. Д. Проблема в том, как разрешить услугу из в моем переопределении IsValid (object, ValidationContext)
переопределение ValidationAttribute
?
Мне нужно пройти через распознаватель зависимостей текущего контроллера в контекст проверки. Я вижу, что ValidationContext
как реализует IServiceProvider
, так и имеет экземпляр IServiceContainer
- так что очевидно, что я смогу создать оболочку для моего распознавателя служб, которая также реализует один из них (вероятно IServiceProvider
).
I ' Мы уже отметили, что во всех местах, где ValidationContext
создается платформой MVC, поставщик услуг всегда передает значение null.
Итак, в какой точке конвейера MVC мне следует хотите переопределить основное поведение и внедрить моего поставщика услуг?
Я должен добавить, что это , а не будет единственным сценарием, в котором мне нужно сделать что-то вроде этого - так что в идеале я бы хотел что-то который я могу применить к конвейеру, чтобы все ValidationContext
были настроены с текущим поставщиком услуг для текущего контроллера.