1

UnitOfWorkAttribute と呼ばれる私の ActionFilter にプロパティを挿入しようとしています。私はこのコードを持っています:

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

それが実行される前に、Ni​​nject にこれを解決するように指示します。

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ます。あなたがする必要がある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 インスタンスがカスタム アクション フィルター内に取り込まれます。

于 2012-08-02T16:49:24.003 に答える