2016-02-27 4 views
0

Je voudrais résoudre un service générique ouvert en raison d'une interface générique. J'utilise autofac.Enregistrer et résoudre les types génériques ouverts avec de nombreux paramètres génériques avec Autofac

Chaque service de béton ne fonctionne qu'avec des classes de béton. Je ne peux résoudre qu'un seul service avec generic param [voir SingleOpenGenericResolveTest]. Est-il possible d'enregistrer & résoudre de nombreux services avec de nombreux T-params [voir MultiOpenGenericResolveTest]?

J'ai ajouté une seule des classes concrètes pour IService mais il est possible d'avoir plusieurs classes de T. (TRegion : Region, TRegion : BigRegion, etc ...)

Voici NUnit 3 tests ou vous pouvez télécharger ici ma solution: https://www.dropbox.com/s/vqmdwb6hwmzgjrb/AutofacResolveTests.zip?dl=0

using System; 
using NUnit.Framework; 
using Autofac; 
using System.Reflection; 
using System.Linq; 

namespace AutofacResolveTests 
{ 
    public class Address<TCity, TRegion, TSomethingElse> 
     where TCity : City<TRegion>, new() 
     where TRegion : Region, new() 
     where TSomethingElse : SomethingElse, new() 
    { 
     public int Id { get; set; } 
     TCity City { get; set; } 
     TRegion Region { get; set; } 
     TSomethingElse SomethingElse { get; set; } 
    } 

    public class City<TRegion> 
     where TRegion : Region, new() 
    { 
     public int Id { get; set; } 
     TRegion Region { get; set; } 
    } 

    public class Region 
    { 
     public int Id { get; set; } 
    } 

    public class SomethingElse 
    { 
     public int Id { get; set; } 
    } 

    public interface IService<T> where T : class 
    { 
     void DoSomething(T entity); 
    } 

    public class AddressService<TAddress, TCity, TRegion, TSomethingElse> : IService<TAddress> 
     where TAddress : Address<TCity, TRegion, TSomethingElse> 
     where TCity : City<TRegion>, new() 
     where TRegion : Region, new() 
     where TSomethingElse : SomethingElse, new() 
    { 
     public void DoSomething(TAddress entity) 
     { 
      Console.WriteLine("Hello from address service"); 
     } 
    } 

    public class CityService<TCity, TRegion> : IService<TCity> 
     where TCity : City<TRegion>, new() 
     where TRegion : Region, new() 
    { 
     public void DoSomething(TCity entity) 
     { 
      Console.WriteLine("Hello from city service"); 
     } 
    } 

    public class RegionService<TRegion> : IService<TRegion> 
     where TRegion : Region 
    { 
     public void DoSomething(TRegion entity) 
     { 
      Console.WriteLine("Hello from region service"); 
     } 
    } 

    [TestFixture] 
    public class OpenGenericResolveTests 
    { 
     IContainer _ioc; 

     [SetUp] 
     public void Setup() 
     { 
      var container = new ContainerBuilder(); 
     //manual types registration - works 
     /* 
     container.RegisterType(typeof(CityService<City<Region>, Region>)).As(typeof(IService<City<Region>>)).AsImplementedInterfaces(); 
     container.RegisterType(typeof(AddressService< 
      Address<City<Region>, Region, SomethingElse>, City<Region>, Region, SomethingElse 
      >)) 
      .As(typeof(IService< 
      Address<City<Region>, Region, SomethingElse> 
      >)).AsImplementedInterfaces(); 
     */ 

      var type = typeof(IService<>); 
      //just get all services which implements IService 
      var generics = type.Assembly.GetTypes().Where(x => 
      !x.IsInterface 
      && x.Name.Contains("Service") 
      && x.IsGenericType 
      && x.GetInterfaces().Any(i => i.GetGenericTypeDefinition() == type) 
      ); 

      foreach (var svcType in generics) 
      { 
       container.RegisterGeneric(svcType) 
       .As(typeof(IService<>)) 
       .AsImplementedInterfaces(); 
      } 

      _ioc = container.Build(); 
     } 

     [Test] 
     public void SingleOpenGenericResolveTest() 
     { 
      var reg = new Region { }; 

      var actual = _ioc.Resolve<IService<Region>>(); 
      Assert.That(actual != null); 

      actual.DoSomething(reg); 
     } 

     [Test] 
     public void MultiOpenGenericResolveTest() 
     { 
      //works 
      var actual1 = _ioc.Resolve<IService<Region>>(); 
      Assert.That(actual1 != null); 

      //works only with manual registration 
      var actual2 = _ioc.Resolve<IService<City<Region>>>(); 
      Assert.That(actual2 != null); 

      //works only with manual registration 
      var actual3 = _ioc.Resolve<IService<Address<City<Region>,Region,SomethingElse>>>(); 
      Assert.That(actual3 != null); 
     } 
    } 
} 

Répondre

0

Le problème est que si vous résoudre IService<T> mais la mise en œuvre prend plus d'un générique comme Service<T,U,V> alors Autofac ne sait pas d'où viennent les autres types (U, V) ... Donc, la façon dont vous essayez de les enregistrer en masse ne fonctionnera pas.

+0

Ok. Je l'ai compris. Mais peut-on trouver tous les types (TRegion: Region) par type de racine (TCity: City) et enregistrer le service en utilisant la réflexion ou un événement dans Autofac: OnActivating, OnPreparing ...? –