Asp.Net MVC3: Установите пользовательский IServiceProvider в ValidationContext, чтобы валидаторы могли разрешать службы

Обновление 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 были настроены с текущим поставщиком услуг для текущего контроллера.

11
задан Andras Zoltan 18 December 2012 в 15:55
поделиться