MVC 3 的温莎城堡依赖解析器

发布于 2024-10-01 07:44:36 字数 3564 浏览 2 评论 0原文

由于 MVC 3 中的 IoC/DI 实现很可能是 RC 中的最终形式,因此我正在寻找使用 Caste Windsor 的 DependencyResolver、IControllerActivator 和 IViewPageActivator 的更新实现。是否有任何已针对 MVC 3 RC 进行更新的示例?

编辑#1 实现 Windsor 依赖解析器确实很简单,但仍然缺少一些东西。与 Jeff Putz 的 Ninject 示例(如下)相反,它似乎不像 Windsor 那样简单。像这样设置依赖解析器后,

DependencyResolver.SetResolver(new WindsorDependencyResolver(container)); 

Windsor 会抛出 ComponentNotFoundException。我需要提供 IControllerFactory 和 IControllerActivator 的实现。由于 DefaultControllerFactory 能够识别 DependencyResolver,因此可以按如下方式解决此问题:

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

WindsorControllerActivator 也很简单。但是,这会导致 IViewPageActivator 出现另一个 ComponentNotFoundException。

这让我相信我错过了一些东西。这不会比实现控制器工厂和调用 ControllerBuilder.Current.SetControllerFactory MVC 2.0 风格更复杂。

编辑#2 我错过了一个微妙但重要的细节,即当找不到服务时依赖解析器需要返回 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[]{};
    }
}

EDIT #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);
    }
}

}

再次强调,这对于使用 Windsor 和 MVC3 依赖项解析器使用基本 DI 来说并不是必需的。

编辑#4 根据一些进一步的研究和反馈,传统的控制器工厂实现似乎是 Windsor 和 MVC3 的最佳方法。令人担忧的是 IDependencyResolver 接口缺少释放方法,这可能会导致 Windsor 不释放其组件而导致内存泄漏。如果所有依赖项都通过 PerWebRequest 生命周期解决,这可能不会成为问题,但最好不要冒险。下面是 MVC3 的 Windsor 控制器工厂的基本实现。

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;
    }

Since the IoC/DI implementation in MVC 3 is most likely in its final form in the RC, I'm looking for an updated implementation of the DependencyResolver, IControllerActivator and IViewPageActivator using Caste Windsor. Are there any examples out there that have been updated for MVC 3 RC?

EDIT #1
Implementing a Windsor dependency resolver is indeed trivial, but there's still something missing. Contrary to Jeff Putz's Ninject example (below), it appears that it's not as simple as that with Windsor. After setting the dependency resolver like so,

DependencyResolver.SetResolver(new WindsorDependencyResolver(container)); 

Windsor throws ComponentNotFoundException. I need to provide implementations for IControllerFactory and IControllerActivator. Since the DefaultControllerFactory is DependencyResolver aware, this can be solved as follows:

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

WindsorControllerActivator is trivial as well. However, this leads to another ComponentNotFoundException for IViewPageActivator.

This leads me to believe that I'm missing something. There is no way that this should be more complicated than an implementing a controller factory and calling ControllerBuilder.Current.SetControllerFactory MVC 2.0-style.

EDIT #2
I missed the subtle but important detail that the Dependency resolver needs to return null when a service cannot be found. The implementation is as follows:

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[]{};
    }
}

EDIT #3

Responding to a question in the comments. If you do find that you need your own IControllerActivator, here a simple implementation for 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);
    }
}

}

Again, this is NOT necessary to get basic DI working with Windsor and the MVC3 dependency resolver.

EDIT #4
Based on some further research and feedback, it seems that a traditional controller factory implementation is the best approach for Windsor and MVC3. The concern is that the IDependencyResolver interface lacks a release method, which could cause memory leaks with Windsor not disposing its components. This is probably not going to be an issue if all of your dependencies are resolved with the PerWebRequest lifecycle, but it's still better not to take the chance. Here's a basic implementation of a Windsor controller factory for 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);
    }
}

EDIT #5
If you're using MVC areas, the above implementation will not work for you. You will need to register each controller based on its full name, and override GetControllerInstance instead of CreateController:

 protected override IController GetControllerInstance(RequestContext context, Type controllerType)
    {
        if (controllerType != null)
        {
            return (IController)container.Kernel.Resolve(controllerType);
        }
        return null;
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不打扰别人 2024-10-08 07:44:36

MVC3 IDependencyResolver接口有一个很大的问题:没有release方法。这意味着如果您打算将其与 Windsor 一起使用,则存在潜在的内存泄漏。请参阅我的博客文章:

http://mikehadlow .blogspot.com/2011/02/mvc-30-idependencyresolver-interface-is.html

The MVC3 IDependencyResolver interface has a big problem: no release method. This means that there is a potential memory leak if you are going to use it with Windsor. See my blog post about it here:

http://mikehadlow.blogspot.com/2011/02/mvc-30-idependencyresolver-interface-is.html

从来不烧饼 2024-10-08 07:44:36

自测试版发布以来,该接口没有发生变化,因此各种框架的所有实现都应该仍然有效。事实上,它的界面并没有那么复杂……您应该能够轻松地推出自己的界面。例如,我为 Ninject 做了这个:

public class NinjectDependencyResolver : IDependencyResolver
{
    public NinjectDependencyResolver(IKernel kernel)
    {
        _kernel = kernel;
    }

    private readonly IKernel _kernel;

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

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

然后将其连接到 global.asax 中,如下所示:

    private static IKernel _kernel;
    public IKernel Kernel
    {
        get { return _kernel; }
    }

    public void Application_Start()
    {
        _kernel = new StandardKernel(new CoreInjectionModule());
        DependencyResolver.SetResolver(new NinjectDependencyResolver(Kernel));
        ...
    }

请记住,此时您可以免费获得各种好东西,包括控制器的 DI、控制器工厂、操作过滤器和视图基类。

编辑:要明确的是,我不确定你的“激活剂”是什么,但你可能不需要它们。 IDependencyResolver 接口自动处理控制器和视图的更新。

The interface has not changed since the beta release, so all of the implementations for various frameworks should still work. And the truth is, it's not that complicated of an interface... you should be able to roll your own without much hassle. For example, I did this one for Ninject:

public class NinjectDependencyResolver : IDependencyResolver
{
    public NinjectDependencyResolver(IKernel kernel)
    {
        _kernel = kernel;
    }

    private readonly IKernel _kernel;

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

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

Then wire it up in global.asax like this:

    private static IKernel _kernel;
    public IKernel Kernel
    {
        get { return _kernel; }
    }

    public void Application_Start()
    {
        _kernel = new StandardKernel(new CoreInjectionModule());
        DependencyResolver.SetResolver(new NinjectDependencyResolver(Kernel));
        ...
    }

Remember, you get all kinds of goodies for free at that point, including DI for controllers, controller factories, action filters and view base classes.

EDIT: To be clear, I'm not sure what your "activators" are, but you probably don't need them. The IDependencyResolver interface handles the newing-up of controllers and views automagically.

挽心 2024-10-08 07:44:36

MVCContrib 目前是 IoC-MVC 集成的权威来源。目前,MVC3 分支仅包括控制器工厂和 IDependencyResolver 实现(以及其他一些东西)。我建议分叉存储库并实现缺少的扩展点(应该不会太难),然后向团队发送拉取请求。

MVCContrib is currently the authoritative source for IoC-MVC integration. Currently, the MVC3 branch only includes controller factory and IDependencyResolver implementations (and a couple other things). I recommend forking the repository and implementing the missing extension points (shouldn't be too hard), then send the team a pull request.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文