2013-04-23 10 views
5

Ich habe einen Dienst mit 2 Abhängigkeiten: ein Repository und ein Gateway (SMS).Auflösen benannter Abhängigkeiten mit Unity

Ich muss 2 verschiedene Versionen des Dienstes auflösen, die sich nur in einem der Parameter unterscheiden, die an das Gateway übergeben werden.

Der Code wird vereinfacht wie folgt

public interface IService 
{ 
    string DoSomething(); 
} 

public interface IServiceFoo 
{ 
    string DoSomething(); 
} 

public interface IServiceBar 
{ 
    string DoSomething(); 
} 

public interface IRepository { } 
public class Repository : IRepository { } 

public interface IGateway 
{ 
    string Name { get; set; } 
} 

public class Gateway : IGateway 
{ 
    public string Name { get; set; } 
    public Gateway(string name) 
    { 
     this.Name = name; 
    } 
} 

public class Service : IService, IServiceFoo, IServiceBar 
{ 
    private readonly IGateway _gateway; 
    private readonly IRepository _repo; 
    public Service(IRepository repo, IGateway gateway) 
    { 
     _gateway = gateway; 
     _repo = repo; 
    } 

    public string DoSomething() 
    { 
     return _gateway.Name; 
    } 
} 

Test Failing

[TestClass] 
public class UnityTest 
{ 
    [TestMethod] 
    public void TestMethod1() 
    { 
     var container = new UnityContainer(); 
     container 
      .RegisterType<IRepository, Repository>() 
      .RegisterType<IGateway, Gateway>("FooGateway", new InjectionConstructor("I am foo")) 
      .RegisterType<IGateway, Gateway>("BarGateway", new InjectionConstructor("I am bar")) 
      .RegisterType<IServiceFoo, Service>(new InjectionConstructor(new ResolvedParameter<IRepository>(), new ResolvedParameter<IGateway>("FooGateway"))) 
      .RegisterType<IServiceBar, Service>(new InjectionConstructor(new ResolvedParameter<IRepository>(), new ResolvedParameter<IGateway>("BarGateway"))); 

     var barGateway = container.Resolve<IGateway>("BarGateway"); 
     var fooGateway = container.Resolve<IGateway>("FooGateway"); 

     var serviceBar = container.Resolve<IServiceBar>(); 
     var serviceBarGatewayName = serviceBar.DoSomething(); 

     var serviceFoo = container.Resolve<IServiceFoo>(); 
     var serviceFooGatewayName = serviceFoo.DoSomething(); 

     Assert.AreEqual("I am bar", barGateway.Name); // pass 
     Assert.AreEqual("I am foo", fooGateway.Name); // pass 


     Assert.AreEqual("I am bar", serviceBarGatewayName); // pass 
     Assert.AreEqual("I am foo", serviceFooGatewayName); // FAIL 

Die falsche Gateway übergeben wird, wenn der Dienst behoben ist, aber wenn ich namentlich das Gateway explizit lösen, es kommt richtig heraus. Ich denke, ich vermisse etwas Grundlegendes wie ResolvedParameter (String-Name) funktioniert, aber ich nahm an, dass es nach einem Typ in dem Container mit diesem Namen sucht.

+0

mit ParameterOverride wie getan werden von InjectionConstructor, so dass Sie einen expliziten Code anstelle von ResolvedParameter haben. Dies sollte funktionieren, aber ich kann nicht beantworten, warum dies nicht mit Ihrer Version funktioniert. –

+0

@WiktorZychla Ich habe eine injectionfactory versucht, aber hatte ähnliche Ergebnisse, wo in diesem Zusammenhang das falsche Gateway gelöst wurde, obwohl ich es mit Namen aufgelöst habe. Ich werde am Morgen mit diesem vereinfachten Beispiel noch einmal versuchen und den Testfall mit den Ergebnissen aktualisieren. – drch

+0

Werde es auch morgen versuchen. Es ist 22 Uhr hier, also melde ich mich am Morgen. –

Antwort

5

haben aber keine Ahnung, warum Ihre Version nicht funktioniert, aber das tut der Arbeit (wie ich es erwartet habe):

 var container = new UnityContainer(); 
     container 
      .RegisterType<IRepository, Repository>() 
      .RegisterType<IGateway, Gateway>("FooGateway", new InjectionConstructor("I am foo")) 
      .RegisterType<IGateway, Gateway>("BarGateway", new InjectionConstructor("I am bar")) 
      //.RegisterType<IServiceFoo, Service>(new InjectionConstructor(new ResolvedParameter<IRepository>(), new ResolvedParameter<IGateway>("FooGateway"))) 
      //.RegisterType<IServiceBar, Service>(new InjectionConstructor(new ResolvedParameter<IRepository>(), new ResolvedParameter<IGateway>("BarGateway"))); 
      .RegisterType<IServiceFoo>(new InjectionFactory(c => new Service(c.Resolve<IRepository>(), c.Resolve<IGateway>("FooGateway")))) 
      .RegisterType<IServiceBar>(new InjectionFactory(c => new Service(c.Resolve<IRepository>(), c.Resolve<IGateway>("BarGateway")))); 

Bitte beachte, dass ich InjectionFactory statt InjectionConstructor verwenden.

Noch eine andere Version, die funktioniert. Dieses Mal habe ich halten Sie Ihre Art und Weise Dienste der Registrierung aber ich mache sie beim Namen genannt und lösen:

 var container = new UnityContainer(); 
     container 
      .RegisterType<IRepository, Repository>() 
      .RegisterType<IGateway, Gateway>("FooGateway", new InjectionConstructor("I am foo")) 
      .RegisterType<IGateway, Gateway>("BarGateway", new InjectionConstructor("I am bar")) 
      .RegisterType<IServiceFoo, Service>("sf", new InjectionConstructor(new ResolvedParameter<IRepository>(), new ResolvedParameter<IGateway>("FooGateway"))) 
      .RegisterType<IServiceBar, Service>("sb", new InjectionConstructor(new ResolvedParameter<IRepository>(), new ResolvedParameter<IGateway>("BarGateway"))); 
      //.RegisterType<IServiceFoo>(new InjectionFactory(c => new Service(c.Resolve<IRepository>(), c.Resolve<IGateway>("FooGateway")))) 
      //.RegisterType<IServiceBar>(new InjectionFactory(c => new Service(c.Resolve<IRepository>(), c.Resolve<IGateway>("BarGateway")))); 


     var barGateway = container.Resolve<IGateway>("BarGateway"); 
     var fooGateway = container.Resolve<IGateway>("FooGateway"); 

     var serviceBar = container.Resolve<IServiceBar>("sb"); 
     var serviceBarGatewayName = serviceBar.DoSomething(); 

     var serviceFoo = container.Resolve<IServiceFoo>("sf"); 
     var serviceFooGatewayName = serviceFoo.DoSomething(); 
+0

Danke - Ich hatte die Injektionsfabrik früher mit den gleichen Ergebnissen versucht, aber ich muss etwas falsch gemacht haben. – drch

+0

* Seufz * obwohl dies im Test von der Frage gelöst wurde, als ich es zu meinem Test gegen das tatsächliche (das zu diesem genauen Aufbau unter Verwendung der Fälschungen vereinfacht wurde) verschoben wurde, verhielt sich der InjectionFactory Ansatz das selbe wie mein ursprüngliches Problem. Ich denke, ich bin mit der Verwendung von Namen in .Resolve() fest, wie Sie als eine zweite Lösung hingewiesen haben. Prost. – drch

+0

Wenn ich Sie wäre, würde ich ein Problem auf ihrer Codeplex-Website öffnen. Wahrscheinlich ist dies ein unerwartetes Verhalten und könnte möglicherweise irgendwie behoben werden. Wenn Sie sich Ihren Code ansehen, würde wahrscheinlich jeder erwarten, dass er funktioniert, während er es nicht tut. Auf der anderen Seite, wenn sie die Einreichung ablehnen, werden sie zumindest irgendwie erklären, was falsch ist. –

1

kann es auch könnten Eine Abhilfe stattdessen zu verwenden InjectionFactory sein unter

 container 
      .RegisterType<IRepository, Repository>() 
      .RegisterType<IGateway, Gateway>("FooGateway", new InjectionConstructor("I am foo")) 
      .RegisterType<IGateway, Gateway>("BarGateway", new InjectionConstructor("I am bar")) 
      .RegisterType<IServiceFoo, Service>(new InjectionConstructor(new ResolvedParameter<IRepository>(), typeof(IGateway))) 
      .RegisterType<IServiceBar, Service>(new InjectionConstructor(new ResolvedParameter<IRepository>(), typeof(IGateway))); 

     var barGateway = container.Resolve<IGateway>("BarGateway"); 
     var fooGateway = container.Resolve<IGateway>("FooGateway"); 

     var serviceBar = container.Resolve<IServiceBar>(new ParameterOverride("gateway", barGateway)); 
     var serviceBarGatewayName = serviceBar.DoSomething(); 

     var serviceFoo = container.Resolve<IServiceBar>(new ParameterOverride("gateway", fooGateway)); 
     var serviceFooGatewayName = serviceFoo.DoSomething(); 

     Assert.AreEqual("I am bar", barGateway.Name); // pass 
     Assert.AreEqual("I am foo", fooGateway.Name); // pass 


     Assert.AreEqual("I am bar", serviceBarGatewayName); // pass 
     Assert.AreEqual("I am foo", serviceFooGatewayName); // pass 
Verwandte Themen