2014-12-04 12 views
9

Wir versuchen, Ninject innerhalb einer OWIN mit WebAPI-Pipeline zu verwenden. Wir haben alles nach this documentation eingerichtet, aber wir können InRequestScope() nicht zum Laufen bringen.Verwenden von Ninject mit Owin und InRequestScope

Hier ist der wesentliche Teil der 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 sieht ungefähr so ​​aus:

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

Unser ApplicationModule wohnt in einem separaten Infrastrukturprojekt mit Zugang zu allen von unseren verschiedenen Schichten, zur Handhabung von DI & Kartierung:

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

Dann haben wir ein paar Schnittstellen:

public interface IUnitOfWork() 
{ 
    void SaveChanges(); 

    Task SaveChangesAsync(); 
} 

und

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

dann unsere tatsächlichen Klassen diese:

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

Einiges Dal

public class SomeDal : IDal { 

    private ApplicationContext _applicationContext; 

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

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

Unsere EF DbContext

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

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

} 

Die Erwartung ist, dass für jede Anforderung eine einzelne Instanz Application erstellt und in die Business-Objekte als IUnitOfWork Implementierung und in die IDals als Application injiziert wird.

Stattdessen wird eine neue Instanz von ApplicationContext für jede einzelne Klasse erstellt, die sie verwendet. Wenn ich den Bereich von InRequestScope auf InSingletonScope umschalte, wird (wie erwartet) genau eine Instanz für die gesamte Anwendung erstellt und ordnungsgemäß in die angegebenen Klassen eingefügt. Da dies funktioniert, gehe ich davon aus, dass dies kein bindendes Problem ist, sondern ein Problem mit der InRequestScope-Erweiterung.

Das einzige Problem, das ich ähnlich finden könnte, was ich erfahre, ist this one, aber leider hat die Lösung nicht funktioniert. Ich verweise bereits auf alle Pakete, die er in den Projekten WebApi und Infrastructure angegeben hat, und ich überprüfe, ob sie in das Erstellungsverzeichnis kopiert werden.

Was mache ich falsch?

Bearbeiten: Einige zusätzliche Informationen. Betrachtet man den Ninject-Quellcode sowohl in Ninject.Web.WebApi.OwinHost als auch in Ninject.Web.Common.OwinHost, so scheint es, als ob Owin Middleware den OwinWebApiRequestScopeProvider als IWebApiRequestScopeProvider hinzufügt. Dieser Provider wird dann in der Erweiterungsmethode InRequestScope() verwendet, um einen benannten Bereich namens "Ninject_WebApiScope" zurückzugeben. Dies wird bis zur Zielklasse vorhanden sein, die in Switches injiziert wird. Der benannte Bereich verschwindet dann und ein neuer Bereich wird erstellt. Ich denke, das ist möglicherweise, worauf sich @BatteryBackupUnit in ihrem Kommentar bezieht, aber ich weiß nicht, wie ich es korrigieren soll.

+1

Meine Vermutung wäre, dass Ihre zweite 'Bind ()' dies verursacht. Sie setzen es nicht auf "InRequestScope()" – LukeP

+0

Leider hat das nicht funktioniert. Ich habe auch versucht, nur den ApplicationContext an InRequestScope zu binden und dann nur IUnitOfWork ToMethod (ctx => ctx.Kernel.Get ()) zu binden. InRequestScope() – aasukisuki

+1

Funktioniert '.InRequestScope()' für * any * verbindlich? Es gibt ein "bekanntes" Problem im Zusammenhang mit der ninjet-nugget-Paketinstallation/-aktualisierung, bei der es nicht korrekt eingerichtet ist und das Request-Scope-spezifische ninject-Zeug nicht korrekt registriert ist. '.InRequestScope()' hat keine Wirkung - leider keine Ausnahme. – BatteryBackupUnit

Antwort

4

Dieser Thread bezieht sich auf dieses Problem ...

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

Ich habe festgestellt, dass das Verhalten von InRequestScope je nach zu ändern scheint, wie Sie sie injizieren. Zum Beispiel ...

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

Ninject erstellt und injiziert dieselbe Instanz von IValuesProvider. Wenn die Methode jedoch wie folgt geschrieben wurde:

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

... werden zwei neue Instanzen erstellt.

+0

Wir landeten auf SimpleInjector, aber diese Antwort war die beste und wies darauf hin, dass dies ein bekannter Fehler in Ninject ist – aasukisuki

3

Basierend auf den Informationen im Link in @ Mick's Beitrag habe ich meine eigene Erweiterungsmethode so hinzugefügt. Ich bin mir nicht sicher über die Schattenseiten.

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

Ich überlege, wegen dieses Problems in einen anderen Container zu wechseln.

Verwandte Themen