2012-08-02 67 views
1

我正在嘗試將一個屬性注入到我的一個名爲UnitOfWorkAttribute的ActionFilter中。我有這樣的代碼:用Ninject注入MVC​​ 3中的屬性

[Inject] 
public IUnitOfWork UnitOfWork { get; set; } 

在此之前得到執行,我告訴Ninject一起解決此問題:

Bind<IUnitOfWork>().To<NHibernateUnitOfWork>().InThreadScope(); 

我的問題是,在我的UnitOfWorkAttribute類,每當我試圖用我的UnitOfWork屬性,它通過爲空。這是我的接口:

public interface IUnitOfWork : IDisposable 
{ 
    void Begin(); 
    void Commit(); 
    void Rollback(); 
} 

,這是我具體:

public interface INHibernateUnitOfWork : IUnitOfWork 
{ 
    ISession Session { get; } 
} 

public class NHibernateUnitOfWork : INHibernateUnitOfWork 
{ 
    private readonly ISessionSource sessionSource; 
    private ITransaction transaction; 
    private ISession session; 

    private bool disposed; 
    private bool begun; 

    public NHibernateUnitOfWork(ISessionSource sessionSource) 
    { 
     this.sessionSource = sessionSource; 
     Begin(); 
    } 

    //....... 
} 

我履行//下的接口......

什麼我錯在這裏做?

回答

6

問題是Ninject從來沒有機會在ActionFilter上「做這件事」,這是在MVC內部由FilterAttributeFilterProvider處理的。你需要做的是告訴MVC使用自定義FilterAttributeFilterProvider,你可以在它們被執行之前攔截過濾器。請允許我以證明:

說我有這個接口和實現:

public interface IFoo 
{ 

} 

public class Foo : IFoo 
{ 

} 

然後,我有一個ActionFilter:

public class MyActionFilterAttribute : ActionFilterAttribute 
{ 
    public MyActionFilterAttribute() 
    { 
    } 

    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     //do something with Foo 
     base.OnActionExecuting(filterContext); 
    } 

    [Inject] 
    public IFoo Foo { get; set; } 
} 

然後我們有一個控制器:

public class HomeController : Controller 
{ 
    [MyActionFilter] 
    public ActionResult Index() 
    { 
     return View(); 
    } 
} 

如果你現在按原樣運行,顯然Foo在MyActionFilter中仍然是null,所以讓我們k EEP去....

讓我們建立了Ninject DependencyResolver:

public class NinjectDependencyResolver : IDependencyResolver 
{ 
    private readonly IKernel _kernel; 

    public NinjectDependencyResolver(IKernel kernel) 
    { 
     _kernel = kernel; 
    } 

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

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

現在讓我們使用的是在Global.asax:

protected void Application_Start() 
    { 
     AreaRegistration.RegisterAllAreas(); 

     RegisterGlobalFilters(GlobalFilters.Filters); 
     RegisterRoutes(RouteTable.Routes); 

     DependencyResolver.SetResolver(new NinjectDependencyResolver(GetKernel())); 
    } 

    private IKernel GetKernel() 
    { 
     var kernel = new StandardKernel(); 
     kernel.Bind<IFoo>().To<Foo>(); 
     return kernel; 
    } 

越來越近了,但仍然MVC不有創建動作過濾器時使用Ninject內核的方法。這是我們將要實現的目標。

第一:

public class NinjectFilterProvider : FilterAttributeFilterProvider 
{ 
    private readonly IKernel _kernel; 

    public NinjectFilterProvider(IKernel kernel) 
    { 
     _kernel = kernel; 
    } 

    public override IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) 
    { 
     var filters = base.GetFilters(controllerContext, actionDescriptor); 

     foreach (var filter in filters) 
     { 

      _kernel.Inject(filter.Instance); 
     } 

     return filters; 
    } 
} 

這裏發生的事情是,我們正在創建一個自定義FilterAttributeFilterProvider類。在OnActionExecuting方法中,在我們通過基礎實現獲取所有過濾器之後,我們可以調用Ninjects Inject方法,該方法將檢查實例並查看它是否可以向其中注入任何內容(使用Inject屬性)。

的最後一塊拼圖是建立我們的定製FilterAttributeFilterProvider綁定:

全球。ASAX:

private IKernel GetKernel() 
    { 
     var kernel = new StandardKernel(); 
     kernel.Bind<IFoo>().To<Foo>(); 
     //use our custom NinjectFilterProvider 
     kernel.Bind<IFilterProvider>().To<NinjectFilterProvider>(); 
     return kernel; 
    } 

現在,當MVC去得到一個IFilterProvider(它通過DependencyResolver會自動完成),它不會得到默認FilterAttributeFilterProvider而是會得到我們的定製NinjectFilterProvider,因此我們的富實例將在自定義動作過濾器中填充。

+2

這很好,但很大程度上不需要。 Ninject.MVC提供了一個很好的叫做BindFilter的小功能,你可以在這裏閱讀它https://github.com/ninject/ninject.web.mvc/wiki/Filter-configurations – 2012-08-02 16:55:22

+0

@MystereMan只有一種方法可以做事嗎? – BFree 2012-08-02 16:59:33

+0

不,但有點像給他人配方時,他們想知道的是他們可以得到一些餅乾。 – 2012-08-02 17:01:46