1

При создании нового элемента при отправке информации из формы обратно в контроллер говорится, что конструктор без параметров не найден. Это ожидается, поскольку модель представления, используемая в качестве модели представления, зависит от объекта модели домена.Когда вы хотите использовать IDependencyResolver над IModelBinder?

Затем я решил написать свое собственное связующее устройство.

NewItemViewModelBinder

public class NewItemViewModelBinder : DefaultModelBinder { 
    public NewItemViewModelBinder(IKernel kernel) { 
     if (kernel == null) throw new ArgumentNullException("kernel"); 
     this.kernel = kernel; 
    } 

    protected override object CreateModel(ControllerContext controllerContext 
     , ModelBindingContext bindingContext, Type modelType) { 
     return kernel.Get(modelType); 
    } 

    private readonly IKernel kernel; 
} 

Это решение с моделью связующего работал нормально, имеющий зарегистрировав это связующее к ModelBinders.Binders в рамках метода NinjectWebCommon.RegisterServices.

public void RegisterServices(IKernel kernel) { 
    CompositionRoot.ComposeObjectGraph(); 
    ModelBinders 
     .Binders 
     .Add(typeof(NewItemViewModel), new NewItemViewModelBinder(kernel)); 
} 

Кроме того, я также столкнулся с некоторыми другими сообщениями, которые говорили о DependencyResolver. Поэтому я подумал, что если я смогу написать идентификатор зависимостей, который бы разрешил все другие проблемы с созданием, я остался бы без проблем для остальных.

NinjectDependencyResolver

public class NinjectDependencyResolver : NinjectDependencyScope 
    : System.Web.Http.Dependencies.IDependencyResolver 
    , System.Web.Mvc.IDependencyResolver { 
    public NinjectDepencyResolver(IKernel kernel 
     , IDependencyScopeFactory factory) : base(kernel) { 
     if (kernel == null) throw new ArgumentNullException("kernel"); 
     if (factory == null) throw new ArgumentNullException("factory"); 
     this.kernel = kernel; 
    } 

    public IDependencyScope BeginScope() { 
     return factory.Create(kernel.BeginBlock()); 
    } 

    public object GetService(Type serviceType) { 
     return kernel.TryGet(serviceType); 
    } 

    public IEnumerable<object> GetServices(Type serviceType) { 
     return kernel.GetAll(serviceType); 
    } 

    public void Dispose() { base.Dispose(); } 

    private readonly IKernel kernel; 
    private readonly IDependencyScopeFactory factory; 
} 

И после установки этого нового распознаватель как распознаватель зависимостей для MVC,

DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel)); 

он не работает, и у меня была такая же проблема, как параметрируемую меньше конструктора.

Итак, у меня есть три вопроса.

  1. Что я сделал неправильно с подходом DependencyResolver?
  2. В чем преимущества работы с DependencyResolver по сравнению с ModelBinder?
  3. Когда использовать любой из них?
+0

Просто добавьте конструктор параметрирования в модель вашего вида (ошибка вызывается из-за того, что внутри 'DefaultModelBinder' использует' Activator.CreateInstance' для инициализации экземпляра вашей модели представления, но не может, если у него нет конструктора без параметров. –

+0

Да, я знаю это и уже сделал это сначала для исправления. Кроме того, мне не нравится исправлять мой код, поэтому это и есть причина вопроса, в то время как использование инсталляции конструктора лучше всего применять при правильном применении DI. Если бы я использовал значение по умолчанию конструктор, я должен был бы передать ему новый экземпляр модели. В результате я был бы тесно связан с кодом, чего именно следует избегать. –

+0

Если у вас есть конструктор без параметров (в дополнение к вашему существующие конструкторы) вам не нужно _make его передать новый экземпляр модели_ 'DefaultModelBinder' инициализирует его и свяжет ваш va lues –

ответ

2

Согласно Wrox Professional ASP.NET MVC 4, страница 308, вы не должны использовать IDependencyResolver для своего приложения.

ДОЛЖНО БЫТЬ ПОТРЕБЛЕНИЕМ ЗАВИСИМОСТИ ОТ ВАС ПРИМЕНЕНИЕ? Возможно, у вас возникнет соблазн потреблять IDependencyResolver из вашего собственного приложения . Сопротивляй этому искушению. Интерфейс преобразователя зависимостей - это именно то, что требуется MVC - и ничего . Он не предназначен для скрытия или замены традиционного API вашего контейнера для инъекций . Большинство контейнеров имеют сложные и интересные API; на самом деле, это , вероятно, вы выберете свой контейнер на основе API и функций, которые он предлагает больше, чем по любой другой причине.

IDependencyResolver предназначен для питания зависимостей в рамках MVC, а не приложения.

Способ реализации IDependencyResolver следует за service locator (anti-)pattern.

Кроме того, IDependencyResolver не требуется использовать DI с MVC. Лучшей альтернативой является использование IControllerFactory для встраивания зависимостей в контроллеры и использование других точек расширения (таких как IModelBinder) с использованием инсталляции конструктора, а не для обслуживания.

Что касается использования IModelBinder, вы используете хорошую практику с вашим примером, потому что вы выполняете инъекцию конструктора (хотя некоторые могут утверждать, что модели не должны иметь зависимости, но это зависит от дизайна вашей структуры).

Как разработчики, мы всегда стараемся как можно больше обобщать проекты, это, как правило, лучший способ действий. Однако, когда дело доходит до DI, мы должны бороться с этим желанием. Для DI лучше, чтобы каждый класс явно запрашивал собственные зависимости по типу, поэтому очевидно, что класс должен функционировать. Сервисный локатор находится на противоположном конце этого спектра - это черный ящик служб, который может содержать или не содержать все типы, необходимые для запуска приложения, и затрудняет его настройку.

+0

Я не знал, что IDependencyResolver использовал анти-шаблон Service Locator. Спасибо за эту информацию, а также заверили меня в том, что касается использования IModelBinder. Я использую инъекцию конструктора в своей модели, потому что ViewModel взаимодействует с самой моделью, поэтому для существования ViewModel я считаю, что имеет смысл сделать ее зависимой от моей модели, модель которой состоит из всего, что приложение должно отображать для пользователя , Там, где я сомневаюсь, ядро ​​/ контейнер следует использовать только в корне композиции, и мне интересно, можно ли передать его в связующее устройство модели. –

+1

Использование ядра/контейнера таким образом (почти) точно так же, как реализация его в IControllerFactory. Вы, по сути, используете IModelBinder в качестве абстрактной фабрики для создания своей модели. До тех пор, пока вы понимаете, что IControllerFactory и IModelBinder являются частью корня композиции и что вы не должны свободно вводить контейнер по всему вашему приложению, вы в порядке. Я считаю полезным сделать абстракцию фасада вокруг объекта контейнера, как отделить приложение от контейнера, так и для обеспечения того, чтобы контейнер не подвергался злоупотреблениям в приложении. – NightOwl888

+0

Я не понял, что оба «IControllerFactory» и «IModelBinder» были как-то частью корня композиции. Фактически, я регистрирую новое связующее устройство в разделе «RegisterServices» класса «NinjectWebCommon» App_Start, поэтому я хочу убедиться, что я только ссылаюсь на ядро ​​/ контейнер, в котором он находится. Напомню эти рекомендации для других проектов. –

Смежные вопросы