1

我正在尝试将一个属性注入到我的一个名为 UnitOfWorkAttribute 的 ActionFilter 中。我有这个代码:

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

在执行之前,我告诉 Ninject 解决这个问题:

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

我的问题是,在我的 UnitOfWorkAttribute 类中,每当我尝试使用我的 UnitOfWork 属性时,它都会以 Null 的形式出现。这是我的界面:

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

    //.......
}

我正在实现//......下的接口

我在这里做错了什么?

4

1 回答 1

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 中仍然为空,所以让我们继续......

让我们设置 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,因此我们的 Foo 实例将填充到自定义操作过滤器中。

于 2012-08-02T16:49:24.003 回答