Tyl*_*ght 1 c# ninject asp.net-mvc-3
我正在尝试将一个属性注入我的一个名为UnitOfWorkAttribute的ActionFilter中.我有这个代码:
[Inject]
public IUnitOfWork UnitOfWork { get; set; }
Run Code Online (Sandbox Code Playgroud)
在执行之前,我告诉Ninject解决这个问题:
Bind<IUnitOfWork>().To<NHibernateUnitOfWork>().InThreadScope();
Run Code Online (Sandbox Code Playgroud)
我的问题是,在我的UnitOfWorkAttribute类中,每当我尝试使用我的UnitOfWork属性时,它都会显示为Null.这是我的界面:
public interface IUnitOfWork : IDisposable
{
void Begin();
void Commit();
void Rollback();
}
Run Code Online (Sandbox Code Playgroud)
这是我的具体内容:
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();
}
//.......
}
Run Code Online (Sandbox Code Playgroud)
我正在履行//下的界面......
我在这做错了什么?
问题是Ninject永远不会有机会在ActionFilter上"做它的事情",这是由MVC内部处理的FilterAttributeFilterProvider
.您需要做的是告诉MVC使用自定义FilterAttributeFilterProvider
,您可以在执行之前拦截过滤器.请允许我证明:
说我有这个界面和实现:
public interface IFoo
{
}
public class Foo : IFoo
{
}
Run Code Online (Sandbox Code Playgroud)
然后我有一个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; }
}
Run Code Online (Sandbox Code Playgroud)
然后我们有一个控制器:
public class HomeController : Controller
{
[MyActionFilter]
public ActionResult Index()
{
return View();
}
}
Run Code Online (Sandbox Code Playgroud)
如果你现在按原样运行它,显然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);
}
}
Run Code Online (Sandbox Code Playgroud)
现在让我们在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;
}
Run Code Online (Sandbox Code Playgroud)
越来越近了,但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;
}
}
Run Code Online (Sandbox Code Playgroud)
这里发生的是我们正在创建一个自定义的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;
}
Run Code Online (Sandbox Code Playgroud)
现在,当MVC去获取IFilterProvider
(它通过DependencyResolver自动完成)时,它将不会获得默认值,FilterAttributeFilterProvider
而是它将获得我们的自定义NinjectFilterProvider
,因此我们的Foo实例将填充在自定义Action Filter中.