2014-12-04 44 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); 
    } 
} 

我確實考慮切換到另一個容器,因爲這個問題。

相關問題