問題は、Ninject が ActionFilter で「それを行う」機会を得られないことです。これは、MVC で内部的に処理されFilterAttributeFilterProvider
ます。あなたがする必要があるFilterAttributeFilterProvider
のは、フィルターが実行される前にインターセプトできるカスタムを使用するように MVC に指示することです。デモをさせてください:
このインターフェースと実装があるとします:
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 のままになるので、続けましょう....
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 のバインディングを設定することです。
Global.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
され、Foo インスタンスがカスタム アクション フィルター内に取り込まれます。