使用Ninject在MVC 3中注入属性

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)

我正在履行//下的界面......

我在这做错了什么?

BFr*_*ree 6

问题是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中.

  • 这一切都很好,但很大程度上不需要.Ninject.MVC提供了一个很棒的小功能,叫做BindFilter,你可以在这里阅读它https://github.com/ninject/ninject.web.mvc/wiki/Filter-configurations (2认同)