2011-11-20 54 views
8

目前,我有一個自定義的ControllerFactory到我注入我統一容器:使用Unity注入依賴到定製ActionFilter

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

這裏是正在建立起來的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(); 
     } 
    } 
} 

的問題是,在我的自定義ActionFilterAttribute公共屬性不會與任何注射,在執行時它仍然是空的!我看不出爲什麼我的過濾器沒有被容器正確建立。被注入的類型是否正確註冊,就像這樣:

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所遵循的過程幾乎完全相同。我錯過了什麼難題?

+0

出於好奇,爲什麼不能在說這樣做,認證要求,預認證請求等,並緩存它們(會話等),所以他們在那裏爲每個請求,而用戶登錄? –

+0

我最初的目的是封裝這個功能,以便在行動需要時添加它。如果經過審查,我將使用過濾器檢索的數據很大一部分,我當然會將其全局緩存以便在整個應用程序中重用。無論如何,它實際上開始看起來像是一個更簡單的解決方案,無論重用!但我仍然很好奇爲什麼'container.BuildUp'不起作用。 –

+0

我確實找到了這個樣本,很快就會檢查出來。該源代碼也可以在那裏下載http://msdn.microsoft.com/en-us/gg618494 –

回答

8

我會做這個略有不同。我想:

  1. 安裝unity.mvc3 NuGet包

  2. 調用bootstrapped.initialise(),如TXT文檔包添加到項目中

  3. 提到的定義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; 
    } 
} 
 
+1

我很欣賞Unity.Mvc3軟件包的發展方向 - 它很好地使用Unity封裝了Mvc3的依賴關係解決方案。不過,我認爲它不能解決我的問題。如果我在控制器中使用如下過濾器進行裝飾的方法:'[PopulatRoles] public ActionResult Add() {'如何在PopulateRoles ActionFilterAttribute上實現注入?我不能使用構造函數注入,因爲它是一個屬性,我不能使用它的構造函數。因此,我需要在創建時創建屬性。 –

+0

作爲一個附錄,我看到ninject做了一些完全不同的東西,像這樣[link](http://www.planetgeek.ch/2010/11/13/official-ninject-mvc-extension-gets-support-for- mvc3 /)允許構造函數注入過濾器,但我不確定這是否可以用Unity實現。 –

+0

過濾器在MVC內部解決我將不得不在這裏嘗試快速測試。 –