2017-03-24 7 views
1

Ich bin auf der Suche nach dem saubersten Weg zur Lösung der Captive Dependency Problem mit Autofac.Captive Dependency mit Autofac

Ich habe eine kurzlebige Klasse, die pro LifeTimeScope registerd werden:

public class ShortLived 
{ 
    public void DoSomethingUsefull() {} 
} 

Und ich habe eine lange Leben Klasse, die als einzige Instanz registriert. Es hat eine Abhängigkeit von der ShortLived-Klasse:

public class LongLived 
{ 
    private readonly Func<ShortLived> _getCurrentShortLived; 

    public LongLived(Func<ShortLived> getCurrentShortLived) 
    { 
     _getCurrentShortLived = getCurrentShortLived; 
    } 

    public void DoSomethingWithShortLived() 
    { 
     var currentShortLived = _getCurrentShortLived(); 
     currentShortLived.DoSomethingUsefull(); 
    } 
} 

Der folgende Versuch funktioniert nicht. Es löst eine Autofac.Core.DependencyResolutionException aus.

public void CaptiveDependencyTest() 
{ 
    var builder = new ContainerBuilder(); 
    builder.RegisterType<LongLived>() 
     .SingleInstance(); 
    var container = builder.Build(); 

    using (var scope = container.BeginLifetimeScope(b => b.RegisterType<ShortLived>())) 
    { 
     var longLived = scope.Resolve<LongLived>(); 
     longLived.DoSomethingWithShortLived(); 
    } 
} 

Folgendes funktioniert. Aber ich hoffe wirklich, dass es eine bessere Lösung für das Problem gibt, als sich auf eine irgendwie statische Variable zu verlassen.

private static ILifetimeScope currentLifetimeScope; 

public void CaptiveDependencyTest2() 
{ 
    var builder = new ContainerBuilder(); 
    builder.Register(c => 
    { 
     Func<ShortLived> shortLivedFacotry =() => currentLifetimeScope.Resolve<ShortLived>(); 
     return new LongLived(shortLivedFacotry); 
    }) 
    .SingleInstance(); 
    var container = builder.Build(); 

    using (var scope = container.BeginLifetimeScope(b => b.RegisterType<ShortLived>())) 
    { 
     currentLifetimeScope = scope; 
     var longLived = scope.Resolve<LongLived>(); 
     longLived.DoSomethingWithShortLived(); 
    } 
} 

Einige Backround Infos: ich auf einem OWIN gerade arbeite gehostet ASP.Net WebApi2 Micro. Wenn ich andere Dienste anrufe, muss ich Werte aus der currentOwinContext.Request.User.Identity lesen und sie der RequestMessage hinzufügen, die ich an den nächsten Dienst sende. Meine LongLived-Klasse ist ein DelegatingHandler (d. H. Ein Teil des HttpClient "HttpMessageHandler-Pipeline"), und der HttpClient muss .SingleInstance() sein, damit ich nicht für jede Anforderung neue HttpClients instanziieren muss. Die ShortLived-Klasse ist IOwinContext, die in einem LifeTimeScope in der Owin-Pipeline registriert ist.

Anstelle einer statischen Variable für das currentLifeTimeScope konnte ich die HttpConfiguration in Autofac registrieren. Dann könnte ich das currentLifeTimeScope mit httpConfig.DependencyResolver.GetRequestLifetimeScope() erhalten; Ich habe diesen Ansatz noch nicht getestet. Ich hoffe immer noch etwas sauberer zu finden.

Antwort

1

Wenn Typ T mit dem Behälter registriert ist, wird Autofac automatisch Abhängigkeiten von Func lösen, wie Fabriken, die T-Instanzen durch den Behälter erstellen Sie bitte weitere Informationen über Delegate Fabriken

Registrieren kurzlebig Klasse finden wie unten das ist alles funktioniert gut jetzt.

public void CaptiveDependencyTest() 
{ 
    var builder = new ContainerBuilder(); 
    builder.RegisterType<ShortLived>() 
     .SingleInstance(); 
    builder.RegisterType<LongLived>() 
     .SingleInstance(); 
    var container = builder.Build(); 

    //using (var scope = container.BeginLifetimeScope(b => b.RegisterType<ShortLived>())) 
    //{ 
     var longLived = container.Resolve<LongLived>(); 
     longLived.DoSomethingWithShortLived(); 
    //} 
} 

und Sie können auch aus dem Behälter mit nicht mehr benötigt wird, aber am Ende Wahl

direkt lösen