使用 Unity 将依赖项注入自定义 ActionFilter [英] Using Unity to inject dependencies into a custom ActionFilter

查看:19
本文介绍了使用 Unity 将依赖项注入自定义 ActionFilter的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前,我有一个自定义的 ControllerFactory,可以将我的 Unity 容器注入其中:

在 global.asax Application_Start() 中:

var container = InitContainer();DependencyResolver.SetResolver(new UnityDependencyResolver(container));var factory = new UnityControllerFactory(container);ControllerBuilder.Current.SetControllerFactory(工厂);

在控制器工厂中,我将控制器设置为使用自定义 ActionInvoker,如下所示:

protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType){var controller = base.GetControllerInstance(requestContext, controllerType) as Controller;如果(控制器!= null)controller.ActionInvoker = new UnityActionInvoker(_container);返回控制器;}

最后,在我的自定义 ActionInvoker 中,我尝试构建使用 ActionInvokers 容器调用的操作:

protected override ActionExecutedContext InvokeActionMethodWithFilters(控制器上下文控制器上下文,IList过滤器,动作描述符动作描述符,IDictionary<字符串,对象>参数){var builtUpFilters = new List();foreach(过滤器中的IActionFilter actionFilter){builtUpFilters.Add(_container.BuildUp(actionFilter));}返回 base.InvokeActionMethodWithFilters(controllerContext, builtUpFilters, actionDescriptor, parameters);}

以下是正在构建的 ActionFilter 之一的示例:

public class PopulatRolesAttribute : ActionFilterAttribute, IActionFilter{private const string RolesKey = "roles";[依赖]public Func服务{得到;放;}公共 PopulatRolesAttribute(){}公共覆盖无效 OnActionExecuting(ActionExecutingContext filterContext){if (filterContext.Controller.ViewData[RolesKey] == null){filterContext.Controller.ViewData[RolesKey] = Service().GetRoles();}}}

问题是我的自定义 ActionFilterAttribute 上的公共属性从未注入任何东西,它在执行时保持为空!我不明白为什么我的过滤器没有被容器正确构建.被注入的类型已正确注册,如下所示:

container.RegisterInstance(new ChannelFactory(新的 BasicHttpBinding(),new EndpointAddress("http://example.com/ABSApplication/MetadataService.svc")));container.RegisterInstance(() =>container.Resolve().CreateChannel());

并且也被注入到应用程序的其他地方(虽然不是通过 .Buildup).这与 博文.我错过了什么拼图?

解决方案

我的做法略有不同.我会:

  1. 安装 unity.mvc3 nuget 包

  2. 调用包添加到项目中的 txt 文档中提到的 bootstrapped.initialise()

  3. 在初始化到具体类型时定义您的 IMetadataService 映射

  4. 将 IMetadataService 添加到您的构造函数

您的实现与您引用的文章之间的区别在于您使用了 Func,我不确定这是否会给这里的混合带来不同的问题.我不得不想象它确实如此,因为上述方法(没有 Func)对我来说很好用.

布拉德威尔逊的代码在这里对我来说很好用:http://bradwilson.typepad.com/blog/2010/07/service-location-pt4-filters.html

适用部分(请看上面的链接)

Global.asax.cs

<前><代码>protected void Application_Start() {//...var oldProvider = FilterProviders.Providers.Single(f => f 是 FilterAttributeFilterProvider);FilterProviders.Providers.Remove(oldProvider);var 容器 = 新的 UnityContainer();var provider = new UnityFilterAttributeFilterProvider(container);FilterProviders.Providers.Add(provider);//...}

过滤器本身:

<前><代码>使用系统;使用 System.Web.Mvc;使用 Microsoft.Practices.Unity;公共类 InjectedFilterAttribute : ActionFilterAttribute {[依赖]公共 IMathService MathService { 获取;放;}公共覆盖无效 OnResultExecuted(ResultExecutedContext filterContext) {filterContext.HttpContext.Response.Write(String.Format("

过滤器说 2 + 3 是 {0}.

",MathService.Add(2, 3)));}}

和 UnityFilterAttributeFilterProvider.cs

<前><代码>使用 System.Collections.Generic;使用 System.Web.Mvc;使用 Microsoft.Practices.Unity;公共类 UnityFilterAttributeFilterProvider :FilterAttributeFilterProvider {私有 IUnityContainer _container;公共 UnityFilterAttributeFilterProvider(IUnityContainer 容器){_container = 容器;}受保护的覆盖 IEnumerable GetControllerAttributes(控制器上下文控制器上下文,ActionDescriptor actionDescriptor) {var 属性 = base.GetControllerAttributes(controllerContext,动作描述符);foreach(属性中的var属性){_container.BuildUp(attribute.GetType(), 属性);}返回属性;}受保护的覆盖 IEnumerable GetActionAttributes(控制器上下文控制器上下文,ActionDescriptor actionDescriptor) {var 属性 = base.GetActionAttributes(controllerContext,动作描述符);foreach(属性中的var属性){_container.BuildUp(attribute.GetType(), 属性);}返回属性;}}

At the moment, I have a custom ControllerFactory into which I inject my Unity container:

in global.asax Application_Start():

var container = InitContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));

var factory = new UnityControllerFactory(container);
ControllerBuilder.Current.SetControllerFactory(factory);

In the controller factory I set my controllers to use a custom ActionInvoker like so:

protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
    var controller = base.GetControllerInstance(requestContext, controllerType) as Controller;

    if (controller != null)
        controller.ActionInvoker = new UnityActionInvoker(_container);

    return controller;
}

Finally in my custom ActionInvoker, I attempt to buildup actions being invoked using the ActionInvokers container:

protected override ActionExecutedContext InvokeActionMethodWithFilters(
        ControllerContext controllerContext,
        IList<IActionFilter> filters,
        ActionDescriptor actionDescriptor,
        IDictionary<string, object> parameters)
{
    var builtUpFilters = new List<IActionFilter>();

    foreach (IActionFilter actionFilter in filters)
    {
        builtUpFilters.Add(_container.BuildUp<IActionFilter>(actionFilter));
    }

    return base.InvokeActionMethodWithFilters(controllerContext, builtUpFilters, actionDescriptor, parameters);
}

Here is an example of one of the ActionFilters that is being built up:

public class PopulatRolesAttribute : ActionFilterAttribute, IActionFilter
{
    private const string RolesKey = "roles";

    [Dependency]
    public Func<IMetadataService> Service { get; set; }

    public PopulatRolesAttribute()
    {
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.Controller.ViewData[RolesKey] == null)
        {
            filterContext.Controller.ViewData[RolesKey] = Service().GetRoles();
        }
    }
}

The problem is that the public property on my custom ActionFilterAttribute is never injected with anything, it remains null on execution! I cannot see why my filter is not being correctly builtup by the container. The type being injected is registered properly, like so:

container.RegisterInstance(new ChannelFactory<IMetadataService>(
    new BasicHttpBinding(),
    new EndpointAddress("http://example.com/ABSApplication/MetadataService.svc")));

container.RegisterInstance<Func<IMetadataService>>(
    () => container.Resolve<ChannelFactory<IMetadataService>>().CreateChannel());

And is also being injected elsewhere in the application (Although not via .Buildup). This is pretty much the same process followed by this blog post. What piece of the puzzle am I missing?

解决方案

I would do this slightly differently. I would:

  1. install the unity.mvc3 nuget package

  2. call the bootstrapped.initialise() as mentioned in the txt doc the package adds to the project

  3. define your IMetadataService mapping in the initialize to your Concrete type

  4. add IMetadataService to your constructor

The difference between your implementation and the article you references is you use Func, which Im not sure if that adds a different problem to the mix here. I have to imagine it does as the above method (without Func) works fine for me.

Edit: Brad Wilson's code worked just fine for me here: http://bradwilson.typepad.com/blog/2010/07/service-location-pt4-filters.html

Applicable parts (please see the link above)

Global.asax.cs


protected void Application_Start() {
    // ...

    var oldProvider = FilterProviders.Providers.Single(
        f => f is FilterAttributeFilterProvider
    );
    FilterProviders.Providers.Remove(oldProvider);

    var container = new UnityContainer();
    var provider = new UnityFilterAttributeFilterProvider(container);
    FilterProviders.Providers.Add(provider);

    // ...
}

The filter itself:


using System;
using System.Web.Mvc;
using Microsoft.Practices.Unity;

public class InjectedFilterAttribute : ActionFilterAttribute {

    [Dependency]
    public IMathService MathService { get; set; }

    public override void OnResultExecuted(ResultExecutedContext filterContext) {
        filterContext.HttpContext.Response.Write(
            String.Format("

The filter says 2 + 3 is {0}.

", MathService.Add(2, 3)) ); } }

and UnityFilterAttributeFilterProvider.cs


using System.Collections.Generic;
using System.Web.Mvc;
using Microsoft.Practices.Unity;

public class UnityFilterAttributeFilterProvider : FilterAttributeFilterProvider {
    private IUnityContainer _container;

    public UnityFilterAttributeFilterProvider(IUnityContainer container) {
        _container = container;
    }

    protected override IEnumerable GetControllerAttributes(
                ControllerContext controllerContext,
                ActionDescriptor actionDescriptor) {

        var attributes = base.GetControllerAttributes(controllerContext,
                                                      actionDescriptor);
        foreach (var attribute in attributes) {
            _container.BuildUp(attribute.GetType(), attribute);
        }

        return attributes;
    }

    protected override IEnumerable GetActionAttributes(
                ControllerContext controllerContext,
                ActionDescriptor actionDescriptor) {

        var attributes = base.GetActionAttributes(controllerContext,
                                                  actionDescriptor);
        foreach (var attribute in attributes) {
            _container.BuildUp(attribute.GetType(), attribute);
        }

        return attributes;
    }
}

这篇关于使用 Unity 将依赖项注入自定义 ActionFilter的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆