使用Ninject与Owin和InRequestScope

aas*_*uki 9 c# entity-framework ninject asp.net-web-api owin

我们正在尝试使用WebAPI管道在Owin中使用Ninject.我们根据此文档设置了所有内容,但我们无法使InRequestScope()工作.

这是startup.cs的重要部分

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        HttpConfiguration config = new HttpConfiguration();

        // Web API routes
        config.MapHttpAttributeRoutes();

        // Ninject Setup
        app.UseNinjectMiddleware(NinjectConfig.CreateKernel);
        app.UseNinjectWebApi(config);
    }
Run Code Online (Sandbox Code Playgroud)

}

NinjectConfig看起来像这样:

public sealed class NinjectConfig
{
    public static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();

        INinjectModule[] modules =
        {
            new ApplicationModule()
        };       

        instance.Load(modules);

        // Do we still need to do this wtih Owin?
        instance.Bind<IHttpModule>().To<OnePerRequestHttpModule>();
    }
}
Run Code Online (Sandbox Code Playgroud)

我们的ApplicationModule位于一个单独的基础架构项目中,可以访问我们所有不同的层,用于处理DI和映射:

public class ApplicationModule: NinjectModule
{

    public override void Load()
    {
        // IUnitOfWork / EF Setups
        Bind<ApplicationContext>().ToSelf().InRequestScope();

        Bind<IUnitOfWork>().ToMethod(ctx => ctx.Kernel.Get<ApplicationContext>()});

        Bind<ApplicationContext>().ToMethod(ctx => ctx.Kernel.Get<ChromLimsContext>()}).WhenInjectedInto<IDal>();

        // other bindings for dals and business objects, etc.
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我们有几个接口:

public interface IUnitOfWork()
{
    void SaveChanges();

    Task SaveChangesAsync();
}
Run Code Online (Sandbox Code Playgroud)

public interface IDal()
{
    // Crud operations, Sync and Async
}
Run Code Online (Sandbox Code Playgroud)

那么我们的实际课程使用这些:

public class SomeBusinessObject
{
    private IUnitOfWork _uow;
    private IDal _someDal;

    public SomeBusinessObject(IUnitOfWork uow, IDal someDal)
    {
        _uow = uow;
        _someDal = someDal;
    }

    public Task<SomeResult> SaveSomething(Something something)
    {
        _someDal.Save(something);
        _uow.SaveChanges();
    }
}
Run Code Online (Sandbox Code Playgroud)

一些达尔

public class SomeDal : IDal {

    private ApplicationContext _applicationContext;

    public SomeDal(ApplicationContext applicationContext)
    {
        _applicationContext = applicationContext;
    }

    public void Save(Something something)
    {
        _applicationContext.Somethings.Add(something);
    }
}
Run Code Online (Sandbox Code Playgroud)

我们的EF DbContext

public class ApplicationContext : DbContext, IUnitOfWork
{
    // EF DBSet Definitions

    public void SaveChanges()
    {
        base.SaveChanges();
    }

}
Run Code Online (Sandbox Code Playgroud)

期望是对于每个请求,创建单个ApplicationContext实例并将其作为IUnitOfWork实现注入业务对象,并作为ApplicationContext注入IDals.

相反,正在发生的是为每个使用它的类创建一个新的ApplicationContext实例.如果我将范围从InRequestScope切换到InSingletonScope,那么(正如预期的那样)将为整个应用程序创建1个实例,并将其正确注入到指定的类中.由于这有效,我假设这不是一个绑定问题,而是InRequestScope扩展的问题.

我能找到的唯一一个类似于我遇到的问题就是这个问题,但遗憾的是解决方案无效.我已经引用了他在WebApi和Infrastructure项目中指定的所有软件包,我仔细检查以确保它们被复制到构建目录中.

我究竟做错了什么?

编辑: 一些其他信息.看着这两个Ninject.Web.WebApi.OwinHost和Ninject.Web.Common.OwinHost的Ninject源代码,看来该Owin中间件添加OwinWebApiRequestScopeProvider作为IWebApiRequestScopeProvider.然后,在InRequestScope()扩展方法中使用此提供程序返回名为"Ninject_WebApiScope"的命名范围.这将一直存在,直到被注入交换机的目标类.然后,命名的范围将消失,并创建一个新范围.我想这可能是@BatteryBackupUnit在评论中提到的内容,但我不知道如何纠正它.

Mic*_*ick 5

这个帖子与这个问题有关...

https://github.com/ninject/Ninject.Web.WebApi/issues/17

我发现InRequestScope的行为似乎会根据你注入它们的方式而改变.例如...

public ValuesController(IValuesProvider valuesProvider1, IValuesProvider valuesProvider2)
{
    this.valuesProvider1 = valuesProvider1;
    this.valuesProvider2 = valuesProvider2;
}
Run Code Online (Sandbox Code Playgroud)

Ninject将创建并注入相同的IValuesProvider实例.但是如果方法写成......

/// <summary>
/// Initializes a new instance of the <see cref="ValuesController"/> class.
/// </summary>
/// <param name="valuesProvider">The values provider.</param>
public Values2Controller(IKernel kernel)
{
    this.valuesProvider1 = kernel.Get<IValuesProvider>();
    this.valuesProvider2 = kernel.Get<IValuesProvider>();
}
Run Code Online (Sandbox Code Playgroud)

...这将创建两个新实例.