使用Unity将依赖项注入自定义ActionFilter

时间:2011-11-20 05:15:36

标签: c# asp.net-mvc-3 dependency-injection unity-container

目前,我有一个自定义ControllerFactory,我将注入Unity容器:

global.asax中的

Application_Start():

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

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

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

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

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

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

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

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

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

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

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

并且还在应用程序的其他地方注入(尽管不是通过.Buildup)。这与blog post所遵循的流程几乎相同。我错过了哪一块拼图?

1 个答案:

答案 0 :(得分:8)

我会稍微改变一下。我会:

  1. 安装unity.mvc3 nuget包

  2. 调用bootstrap.initialise(),如包中添加到项目的txt文档中所述

  3. 在初始化为Concrete类型

  4. 时定义您的IMetadataService映射
  5. 将IMetadataService添加到构造函数

  6. 您的实现与您引用的文章之间的区别是您使用Func,我不确定这是否会在此处添加不同的问题。我必须想象它确实如上所述(没有Func)对我来说很好。

    编辑: Brad Wilson的代码在这里对我很好: 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 is FilterAttributeFilterProvider
        );
        FilterProviders.Providers.Remove(oldProvider);
    
        var container = new UnityContainer();
        var provider = new UnityFilterAttributeFilterProvider(container);
        FilterProviders.Providers.Add(provider);
    
        // ...
    }
    
    

    过滤器本身:

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

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