Внедрение свойства без атрибутов с использованием Ninject в абстрактном базовом контроллере в MVC3 - PullRequest
2 голосов
/ 29 июня 2011

У меня есть следующий код:

public abstract class BaseController : Controller
{
    public IUserService UserService { get; set; }
}

Все мои контроллеры наследуются от этого базового контроллера.Я начал с настройки его в Ninject, используя следующий код:

kernel.Bind<BaseController>()
      .ToSelf()
      .WithPropertyValue("UserService", x => x.Kernel.GetService(typeof(IUserService)));

Это не сработало.Я предполагаю, что это из-за того, что BaseController является абстрактным классом (пожалуйста, подтвердите мое предположение).Поэтому я перешел к изменению конфигурации:

kernel.Bind<HomeController>()
      .ToSelf()
      .WithPropertyValue("UserService", x => x.Kernel.GetService(typeof(IUserService)));

Это работает.Незначительным недостатком является то, что теперь мне приходится настраивать каждый контроллер одинаково.

Поскольку у меня также есть настройка DependencyResolver в моем проекте ASP.NET MVC 3, я также мог удалить вышеуказанную конфигурацию Ninject и изменить свой базовый контроллер навыглядят так:

    public IUserService UserService
    {
        get
        {
            return DependencyResolver.Current.GetService<IUserService>();
        }
    }

Есть ли какая-либо польза от использования плавной конфигурации по сравнению с использованием подхода DependencyResolver?Один лучше другого?Какой подход будет считаться лучшей практикой?

Стоит отметить, что я не хотел внедрять конструктор в мой базовый контроллер.

Ответы [ 3 ]

2 голосов
/ 30 июня 2011

Если вам нужна одинаковая зависимость в каждом контроллере, значит, в вашем дизайне что-то не так. Скорее всего, вы решаете какую-то сквозную проблему в вашем базовом контроллере. В этом случае делать инъекцию свойства - это просто лечить симптомы, а не лечить болезнь. Это скорее должно быть обработано аспектом (например, фильтром или перехватчиком), чтобы вам не приходилось загрязнять ваш контроллер чем-то, что там не принадлежит.

2 голосов
/ 29 июня 2011

Лучшей практикой в ​​MVC является использование инжектора конструктора поверх свойства. Почему вы сделали такой выбор?

Используя Внедрение в конструктор вы заявляете, что все зависимости в конструкторе необходимы для того, чтобы класс выполнял свою работу.

Внедрение свойства означает, что зависимости являются необязательными или существуют локальные реализации по умолчанию, поэтому все будет работать, даже если вы сами не предоставите необходимые реализации.

Вы должны действительно знать, что вы делаете, используя инъекцию свойств, или у вас нет другого выбора, поэтому более безопасный подход - полагаться на инъекцию в конструктор.

Теперь я дам вам свою точку зрения. У других могут быть другие мнения.

DependencyResolver был введен в MVC 3 для «удобного» расположения сервиса, но для меня это обычный Сервисный локатор , который для меня также является анти-паттерном http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx. Я его не использую потому что мне это не нравится и в этом нет никакой пользы. Я предпочитаю использовать фабрику контроллеров, как раньше, и передавать зависимости через конструктор.

Более того, IDependencyResolver имеет некоторые проблемы с некоторыми контейнерами IoC (я не знаю, так ли это с Ninject). Вы можете прочитать больше здесь: http://mikehadlow.blogspot.com/2011/02/mvc-30-idependencyresolver-interface-is.html

0 голосов
/ 30 июня 2011

Есть много способов снять кожу с кошки, которую они говорят. Вы можете использовать привязки на основе соглашений с .WithPropertyValue() или с .OnActivaction() (как описано здесь ).

public class ControllerModule : NinjectModule
{
    public override void Load()
    {
        // Get all controller types derived from the base controller.
        IEnumerable<Type> controllerTypes = // ...
        foreach (var controllerType in controllerTypes)
        {
            Bind(controllerType).ToSelf().InRequestScope()
                .WithPropertyValue(...);
        }
    }
 }

Вы можете создать свою собственную пользовательскую реализацию интерфейса IInjectionHeuristic, как описано здесь или свою собственную пользовательскую реализацию интерфейса IControllerActivator .

public class CustomNinjectControllerActivator : IControllerActivator
{
    private readonly IKernel kernel;

    public CustomNinjectControllerActivator(IKernel kernel)
    {
        this.kernel = kernel;
    }

    public IController Create(RequestContext context, Type controllerType)
    {
        var baseController = kernel.TryGet(controllerType) as BaseController;
        if (baseController == null)
        {
            return null;
        }

        baseController.UserService = kernel.Get<IUserService>();
        return baseController;
    }
}

Черт возьми, вы даже можете использовать шаблон поиска сервисов, если вам удобно его использовать.

public IUserService UserService
{
    get { return DependencyResolver.Current.GetService<IUserService>(); }
}

Вы должны выбрать, какое решение проще всего внедрить, протестировать и поддерживать, и, конечно же, обеспечивает желаемое поведение.

...