Search code examples
c#autofacgeneric-programming

Autofac with generic services and repository


I'am facing an issue with the architecture set in place while trying to use Autofac.

Error message encountered is the following:

None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'xx.xx.xxxxxxx.HomeController' can be invoked with the available services and parameters: Cannot resolve parameter 'xx.Service.Common.IGenericService2[xx.Common.Models.EntCountry,System.Int32] countryService' of constructor 'Void .ctor(xx.Service.Common.IGenericService2[xx.Common.Models.EntCountry,System.Int32])'.

Repository Interface and Class

 public interface IGenericRepository<T,TId> 
        where T: class , IEntity<TId>
    {...}

 public abstract class GenericRepository<T, TId> : IGenericRepository<T, TId>  
        where T : class, IEntity<TId>
        where TId : class {}

Service Interface and Class

 public interface IGenericService<T,TId> where T : class , IEntity<TId> 
    {...}



public abstract class GenericService<T, TId> : IGenericService<T, TId>  
        where T : class, IEntity<TId> 
        where TId : class{...}

Controller Code

   public class HomeController : Controller
    {

    private readonly IGenericService<EntCountry, int> _countryService;

    public HomeController(IGenericService<EntCountry, int> countryService)
    {
        _countryService = countryService;
    }

    // GET: Home
    public ActionResult Index()
    {

        var countries = _countryService.GetAll();

        return View();
    }
}

My Autofac configuration for services and repository is the following:

builder.RegisterAssemblyTypes(Assembly.Load("XX.Data"))
                   .Where(t => t.Name.EndsWith("Repository"))
                   .AsImplementedInterfaces()
                   .AsSelf()
     .PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies)
                   .InstancePerLifetimeScope();





 builder.RegisterAssemblyTypes(Assembly.Load("XX.Service"))
                   .Where(t => t.Name.EndsWith("Service"))
                   .AsImplementedInterfaces()
                   .AsSelf()
                   .PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies)
                   .InstancePerLifetimeScope();

I tried to use the Register Generic method, but I still got the same error

builder.RegisterGeneric(typeof(GenericRepository<,>))
                .As(typeof(IGenericRepository<,>))
                .AsSelf()
                .InstancePerDependency();

Thanks for your help.

best regards.


Solution

  • The error message indicates that IGenericService<EntCountry, Int32> is not registered.

    Because GenericService is abstract the first solution would be to have an implementation of such a class

    public class FooService : GenericService<Foo, Int32> 
    { }
    

    Then Autofac will register FooService as IGenericService<Foo, Int32>

    If you don't want to have an implementation but only use GenericService<T, TId> you will have to remove the abstract modifier and change how you register your type in Autofac.

    Unfortunately there is no easy way to register an open generic type when scanning assemblies. There is an active open issue about this in Autofac Github : Support registering open generic types when scanning assemblies

    The easiest solution is to register this type manually

    builder.RegisterGeneric(typeof(GenericService<,>))
           .AsImplementedInterfaces();
    

    If it is not possible have a look at the Github issue there is some solution you could play with.


    There will also be another issue with the code provided. The IGenericService<T, TId> has a class constraint (where TId : class) but in the exception TId is a Int32 wich is not valid for the .net runtime. You should remove the class constraint or change the type of TId.