Пример реализации IModelBinderProvider для внедрения конструктора ModelBinder в MVC 3

Мне нужно подключить свой собственный ModelBinder к моему контейнеру DI в MVC 3, но я не могу заставить его работать.

Так. Вот что у меня есть: ModelBinder с сервисом, введенным конструктором.

public class ProductModelBinder : IModelBinder{
  public ProductModelBinder(IProductService productService){/*sets field*/}
  // the rest don't matter. It works.
}

Мой связующий работает нормально, если я добавлю его следующим образом:

ModelBinders.Binders.Add(typeof(Product),
     new ProductModelBinder(IoC.Resolve<IProductService>()));

Но это старый способ сделать это, и я не хочу этого.

Что мне нужно, так это помощь в том, как подключить этот связыватель моделей к IDependencyResolver, который я зарегистрировал.

По словам Брэда Уилсона, секрет заключается в использовании реализации IModelBinderProvider, но очень неясно, как это подключить. (в этом сообщении)

У кого-нибудь есть пример?


person Christian Dalager    schedule 08.12.2010    source источник
comment
IModelBinderProvider будет вашей собственной реализацией. Так получилось, что я написал сообщение в блоге именно об этом buildstarted.com/2010/12/02/ Надеюсь, это поможет   -  person Buildstarted    schedule 08.12.2010
comment
Да, это работает хорошо. Я просто заменяю CreateInstance() на var instance = (IModelBinder) DependencyResolver.Current.GetService(type); Спасибо! .   -  person Christian Dalager    schedule 09.12.2010
comment
Я все еще думаю, что можно сделать более чистую реализацию с использованием дженериков. Мне нужно поспать, я думаю ;)   -  person Christian Dalager    schedule 09.12.2010


Ответы (2)


Я столкнулся с той же ситуацией при кодировании своего приложения MVC 3. Я закончил с чем-то вроде этого:

public class ModelBinderProvider : IModelBinderProvider
{
    private static Type IfSubClassOrSame(Type subClass, Type baseClass, Type binder)
    {
        if (subClass == baseClass || subClass.IsSubclassOf(baseClass))
            return binder;
        else
            return null;
    }

    public IModelBinder GetBinder(Type modelType)
    {
        var binderType = 
            IfSubClassOrSame(modelType, typeof(xCommand), typeof(xCommandBinder)) ??
            IfSubClassOrSame(modelType, typeof(yCommand), typeof(yCommandBinder)) ?? null;

        return binderType != null ? (IModelBinder) IoC.Resolve(binderType) : null;
    }
}

Затем я зарегистрировал это в своем контейнере IoC (в моем случае Unity):

_container.RegisterType<IModelBinderProvider, ModelBinderProvider>("ModelBinderProvider", singleton());

Это работает для меня.

person kidoman    schedule 09.12.2010

Вам нужно написать свой собственный IModelBinderProvider и зарегистрировать его в коллекции ModelBinderProviders.BinderProviders:

public class YourModelBinderProvider : IModelBinderProvider {
    public IModelBinder GetBinder(Type modelType) {
         if(modelType == typeof(Product)) {
             return new ProductModelBinder(...);
         }
         return null;
    }
}

В Global.asax:

ModelBinderProviders.BinderProviders.Add(new YourModelBinderProvider());
person marcind    schedule 08.12.2010
comment
Лучше ли зарегистрировать IModelBinderProvider в IoC, чтобы MVC автоматически запрашивал его, или зарегистрировать его явно с помощью BinderProviders.Add(...) ? Кроме того, если мы пытаемся обрабатывать несколько связующих (в зависимости от типа модели), есть ли шаблон, который вы бы порекомендовали? - person kidoman; 09.12.2010
comment
Вы могли бы сделать это в любом случае. Наверное, я просто предпочитаю традиционный подход. - person marcind; 09.12.2010
comment
Как вы пытаетесь справиться с несколькими связующими? Выигрывает тот поставщик связывателя, который возвращает ненулевой связыватель. Так что это просто вопрос упорядочения вещей соответствующим образом. - person marcind; 09.12.2010
comment
Взгляните на мой ответ ниже... В настоящее время я использую это проект разработки. - person kidoman; 09.12.2010