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

And*_*est 8 c# dependency-injection unity-container asp.net-mvc-3

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

在global.asax Application_Start()中:

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

var factory = new UnityControllerFactory(container);
ControllerBuilder.Current.SetControllerFactory(factory);
Run Code Online (Sandbox Code Playgroud)

在控制器工厂中,我将控制器设置为使用自定义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;
}
Run Code Online (Sandbox Code Playgroud)

最后在我的自定义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);
}
Run Code Online (Sandbox Code Playgroud)

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

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是我的自定义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());
Run Code Online (Sandbox Code Playgroud)

并且还在应用程序的其他地方注入(虽然不是通过.Buildup).这个博客文章跟随的过程几乎相同.我错过了哪一块拼图?

Ada*_*SFT 8

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

  1. 安装unity.mvc3 nuget包

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

  3. 在初始化为Concrete类型时定义IMetadataService映射

  4. 将IMetadataService添加到构造函数中

你的实现和你引用的文章之间的区别是你使用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;
    }
}