2014-12-04 116 views
9

我们试图在Owin中使用Ninject和WebAPI管道。我们根据this documentation设置了一切设置,但我们无法使InRequestScope()正常工作。在Owin和InRequestScope中使用Ninject

这里的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); 
    } 

}的显著部分

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

我们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. 
    } 
} 

然后我们有几个接口:

public interface IUnitOfWork() 
{ 
    void SaveChanges(); 

    Task SaveChangesAsync(); 
} 

public interface IDal() 
{ 
    // Crud operations, Sync and Async 
} 

然后我们使用这些实际类:

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

有些达尔

public class SomeDal : IDal { 

    private ApplicationContext _applicationContext; 

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

    public void Save(Something something) 
    { 
     _applicationContext.Somethings.Add(something); 
    } 
} 

我们EF的DbContext

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

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

} 

的期望是,为每个请求,ApplicationContext中的单个实例被创建和注入业务对象作为IUnitOfWork实现进入IDals作为一个ApplicationContext。

取而代之的是,正在为每个使用它的类创建一个ApplicationContext的新实例。如果我将范围从InRequestScope切换到InSingletonScope,那么(如预期的那样)为整个应用程序创建了一个实例,并将其正确注入到指定的类中。既然这样,我假设这不是一个绑定问题,而是一个InRequestScope扩展的问题。

我可以找到类似于我正在经历的唯一问题是this one,但不幸的是该解决方案无法正常工作。我已经引用了他在WebApi和基础结构项目中指定的所有包,并且我进行了双重检查以确保它们被复制到构建目录中。

我在做什么错?

编辑: 一些额外的信息。查看Ninject.Web.WebApi.OwinHost和Ninject.Web.Common.OwinHost中的Ninject源代码,似乎Owin Middleware将OwinWebApiRequestScopeProvider添加为IWebApiRequestScopeProvider。然后,此提供程序将用于InRequestScope()扩展方法中,以返回名为“Ninject_WebApiScope”的命名范围。这将一直存在,直到注入交换机的目标类为止。命名的作用域消失,并创建一个新的作用域。我认为这可能是@BatteryBackupUnit在他们的评论中提到的,但我不知道如何纠正它。

+1

我的猜测是你的第二个'Bind ()'引起了这个问题。你没有将它设置为'InRequestScope()' – LukeP 2014-12-04 21:06:36

+0

不幸的是,没有工作。我也试过只绑定ApplicationContext到自己的InRequestScope,然后只绑定IUnitOfWork ToMethod(ctx => ctx.Kernel.Get ())。InRequestScope() – aasukisuki 2014-12-04 21:18:21

+1

'.InRequestScope() * 捆绑?有一个与ninject nuget软件包安装/升级相关的“已知”问题,它没有正确设置,并且请求范围特定的注入内容未正确注册。 '.InRequestScope()'没有效果 - 遗憾的是甚至没有抛出异常。 – BatteryBackupUnit 2014-12-05 07:15:37

回答

4

此线程与此问题有关...

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

我发现InRequestScope的行为似乎取决于你如何将它们注入改变。例如...

public ValuesController(IValuesProvider valuesProvider1, IValuesProvider valuesProvider2) 
{ 
    this.valuesProvider1 = valuesProvider1; 
    this.valuesProvider2 = valuesProvider2; 
} 

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

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

+0

我们最终切换到SimpleInjector,但这个答案是最好的,指出这是Ninject中的一个已知错误 – aasukisuki 2016-12-07 15:58:12

3

根据@米克的文章链接中的信息,我最终添加了我自己的扩展方法。我不确定这些缺点。

public static class CustomRequestScope 
{ 
    public static Ninject.Syntax.IBindingNamedWithOrOnSyntax<T> InCustomRequestScope<T>(this Ninject.Syntax.IBindingInSyntax<T> syntax) 
    { 
     return syntax.InScope(ctx => HttpContext.Current.Handler == null ? null : HttpContext.Current.Request); 
    } 
} 

我确实考虑切换到另一个容器,因为这个问题。

相关问题