2013-04-23 18 views
5

Mam usługę z 2 zależnościami: repozytorium i bramę (sms).Rozwiązywanie nazwanych zależności za pomocą Unity

Potrzebuję rozwiązać 2 różne wersje usługi, które różnią się tylko na jednym z parametrów przekazywanych do bramy.

Kod jest uproszczone następująco

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

Niezastosowanie testu

[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 

niewłaściwy brama jest przekazywane w przypadku gdy usługa zostanie rozwiązany, jednak gdybym rozwiązać bramę wyraźnie po imieniu, wychodzi poprawnie. Myślę, że brakuje mi czegoś podstawowego w działaniu parametru ResolvedParameter (nazwa łańcucha), ale założyłem, że szuka on typu w kontenerze o tej nazwie.

+0

Rozwiązaniem może być użycie InjectionFactory zamiast InjectionConstructor, aby mieć jawny kod zamiast ResolvedParameter. To powinno działać, ale nie mogę odpowiedzieć, dlaczego to nie działa z twoją wersją. –

+0

@WiktorZychla Zrobiłem próbę wstrzyknięcia, ale miałem podobne wyniki, gdy w tym kontekście rozwiązano niewłaściwą bramę, mimo że rozwiązałem ją po imieniu. Spróbuję ponownie rano z tym uproszczonym przykładem i zaktualizuję wyniki testu z wynikami. – drch

+0

Spróbuje również tego jutro. Jest tutaj 22.00, więc rano się zgłoszę. –

Odpowiedz

5

Nadal nie mam pojęcia, dlaczego dana wersja nie działa, ale to nie działa (jak mam się spodziewać):

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

Zauważ, że używam InjectionFactory zamiast InjectionConstructor.

Kolejna wersja, która działa. Tym razem zachować swój sposób z usług rejestracji, ale ich imieniem i rozwiązać według nazwy:

 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

Dzięki - wcześniej próbowałem wstrzykiwań z tymi samymi wynikami, ale musiałem zrobić coś nieprawidłowego. – drch

+0

* westchnę * chociaż rozwiązałem to w teście od pytania, kiedy przeniosłem to do mojego testu przeciw faktycznemu (co było uproszczone do tej dokładnej konfiguracji przy użyciu podróbek) podejście InjectionFactory zachowywało się tak samo jak mój pierwotny problem. Myślę, że utknąłem z użyciem nazw w .Resolve(), jak wskazałeś jako drugie rozwiązanie. Twoje zdrowie. – drch

+0

Gdybym był tobą, chciałbym otworzyć problem na ich stronie codeplex. Jest szansa, że ​​jest to nieoczekiwane zachowanie, które można jakoś naprawić. Po prostu patrząc na twój kod, ktoś prawdopodobnie oczekiwałby, że zadziała, podczas gdy nie. Z drugiej strony, jeśli odrzucą zgłoszenie, przynajmniej zapewne jakoś wyjaśnią, co jest nie tak. –

1

może być również wykonywane przy użyciu ParameterOverride jak poniżej

 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 
Powiązane problemy