Castle Windsor Dependency Resolver для MVC 3

Поскольку реализация IoC / DI в MVC 3, скорее всего, находится в окончательной форме в RC, я ищу обновленную реализацию DependencyResolver, IControllerActivator и IViewPageActivator с использованием Caste Windsor. Реализация распознавателя зависимостей Windsor действительно тривиальна, но кое-чего еще не хватает. В отличие от примера Джеффа Путца Ninject (ниже), похоже, что с Виндзором все не так просто. После такой установки преобразователя зависимостей

DependencyResolver.SetResolver(new WindsorDependencyResolver(container)); 

Windsor выдает исключение ComponentNotFoundException. Мне нужно предоставить реализации для IControllerFactory и IControllerActivator. Поскольку DefaultControllerFactory поддерживает DependencyResolver, эту проблему можно решить следующим образом:

Component.For<IControllerFactory >().ImplementedBy<DefaultControllerFactory>()
Component.For<IControllerActivator >().ImplementedBy<WindsorControllerActivator>(),

WindsorControllerActivator также тривиален. Однако это приводит к другому исключению ComponentNotFoundException для IViewPageActivator.

Это наводит меня на мысль, что я чего-то упускаю. Это не может быть более сложным, чем реализация фабрики контроллеров и вызов ControllerBuilder.Current.SetControllerFactory в стиле MVC 2.0. Я упустил тонкую, но важную деталь, что преобразователь зависимостей должен возвращать значение null, если служба не может быть найдена. Реализация следующая:

public class WindsorDependencyResolver : IDependencyResolver
{
    private readonly IWindsorContainer container;

    public WindsorDependencyResolver(IWindsorContainer container)
    {
        this.container = container;
    }

    public object GetService(Type serviceType)
    {
        return container.Kernel.HasComponent(serviceType) ? container.Resolve(serviceType) : null;
    }

  public IEnumerable<object> GetServices(Type serviceType)
    {
        return container.Kernel.HasComponent(serviceType) ? container.ResolveAll(serviceType).Cast<object>() : new object[]{};
    }
}

РЕДАКТИРОВАТЬ # 3

Ответ на вопрос в комментариях. Если вы обнаружите, что вам нужен собственный IControllerActivator, вот простая реализация для Windsor:

public class WindsorControllerActivator : IControllerActivator
{
    private readonly IWindsorContainer container;

    public WindsorControllerActivator(IWindsorContainer container)
    {
        this.container = container;
    }

    public IController Create(RequestContext requestContext, Type controllerType)
    {
        return (IController)container.GetService(controllerType);
    }
}

}

Опять же, это НЕ необходимо для получения базового DI, работающего с Windsor и преобразователем зависимостей MVC3.

РЕДАКТИРОВАТЬ №4 Основываясь на некоторых дальнейших исследованиях и отзывах, кажется, что реализация традиционной фабрики контроллеров - лучший подход для Windsor и MVC3. Проблема заключается в том, что в интерфейсе IDependencyResolver отсутствует метод выпуска, который может вызвать утечку памяти, если Windsor не удалит свои компоненты. Это, вероятно, не будет проблемой, если все ваши зависимости разрешены с помощью жизненного цикла PerWebRequest, но все же лучше не рисковать. Вот базовая реализация фабрики контроллеров Windsor для MVC3.

public class WindsorControllerFactory : DefaultControllerFactory
{
    private readonly IWindsorContainer container;

    public WindsorControllerFactory(IWindsorContainer container)
    {
        this.container = container;
    }

    public override void ReleaseController(IController controller)
    {
        container.Kernel.ReleaseComponent(controller);
    }

    public override IController CreateController(RequestContext requestContext, string controllerName)
    {
        var controllerComponentName = controllerName + "Controller";
        return container.Kernel.Resolve<IController>(controllerComponentName);
    }
}

РЕДАКТИРОВАТЬ №5 Если вы используете области MVC, приведенная выше реализация вам не подойдет. Вам нужно будет зарегистрировать каждый контроллер на основе его полного имени и переопределить GetControllerInstance вместо CreateController:

 protected override IController GetControllerInstance(RequestContext context, Type controllerType)
    {
        if (controllerType != null)
        {
            return (IController)container.Kernel.Resolve(controllerType);
        }
        return null;
    }
32
задан James H 29 April 2011 в 19:13
поделиться