Inject generic interface in .NET Core

27,274

Solution 1

1.) if you want to write hard code

services.AddScoped<IDatabaseService<Project>, ProjectService>();

2.) if you want to register dynamically that all types of implemented IDatabaseService<>

        System.Reflection.Assembly.GetExecutingAssembly()
            .GetTypes()
            .Where(item => item.GetInterfaces()
            .Where(i => i.IsGenericType).Any(i => i.GetGenericTypeDefinition() == typeof(IDatabaseService<>)) && !item.IsAbstract && !item.IsInterface)
            .ToList()
            .ForEach(assignedTypes =>
            {
                var serviceType = assignedTypes.GetInterfaces().First(i => i.GetGenericTypeDefinition() == typeof(IDatabaseService<>));
                services.AddScoped(serviceType, assignedTypes);
            });

Solution 2

You can do this by adding the below line in Startup.cs

// best practice  
services.AddTransient(typeof(IDatabaseService<>),typeof(DatabaseService<>));

Visit Here to know more about Dependency injection in ASP.NET Core

Solution 3

You can use services.AddScoped to use only 1 instance in the scope request. So in general improvement compare to AddTransient

services.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<>));

So my interface and class will look like this

public interface IGenericRepository<T> where T : class
public class GenericRepository<T> : IGenericRepository<T> where T : class

Solution 4

Feel free to use helpers:

by Generic interface

services.AddAllGenericTypes(typeof(IDatabaseService<>), new[] {typeof(ProjectService).GetTypeInfo().Assembly});

With extensions from: https://gist.github.com/GetoXs/5caf0d8cfe6faa8a855c3ccef7c5a541

Share:
27,274
michasaucer
Author by

michasaucer

Updated on July 09, 2022

Comments

  • michasaucer
    michasaucer almost 2 years

    I want to inject this interface to my controllers:

    public interface IDatabaseService<T>
    {
        IEnumerable<T> GetList();
        ...
    }
    

    I want to use generic, because in my WebApi project i have controllers like ProjectController, TaskController etc and i want to use generic interface to each of type (for example, IDatabaseService<Project>, IdatabaseService<Task> etc).

    Class, that will be injected to controller will look like this:

    public class ProjectService : IDatabaseService<Project>
    {
        private readonly DbContext context;
    
        public ProjectService(DbContext context)
        {
            this.context = context;
        }
    
        public IEnumerable<Project> GetList() { }
        ...
    }
    

    But when I try to ineject in my Startup.cs:

    services.AddScoped<IDatabaseService<T>>();
    

    I need to pass T type.

    My question is, how to make injection generic and how inject it properly in controller? For example:

    public class ProjectController : ControllerBase
    {
        private readonly ProjectService projectService;
    
        public ProjectController (IDatabaseService<Project> projectService)
        {
            this.projectService = projectService;
        }
    }
    

    If it will work? And is it good practice to make generic interface to inject into controllers? If no, how to do it better?

  • Tseng
    Tseng almost 5 years
    services.AddTransient<IDatabaseService<T>, DatabaseService<T>>(); this isnt going to work with a generic type, you'd have to add the concrete type instead of T. When using generic parameters, they must be known at compile time. Second line is the only way to register it w/o knowing and defining the concrete type(s) (per type registration)
  • michasaucer
    michasaucer almost 5 years
    I wanted to work only on DbSet with Projects in my mind, so how it work in "real life" scenerios? Its better to deal with one IDatabaseService and DatabaseService if each one controller? I think ProjectController dont need to have (for example) reference to Tasks
  • Voodoo
    Voodoo almost 5 years
    Thanks for the comments. I have removed the wrong example.
  • michasaucer
    michasaucer almost 5 years
    Thanks, but as you can see in my quesion, i wan to have classes like TaskService : IDatabaseService<Task> and ProjectService : IDatabaseService<Project>. I dobt have 'DatabaseService' class
  • michasaucer
    michasaucer almost 5 years
    Could you provide more complex explenation about second paragraph?
  • levent
    levent almost 5 years
    If you have a large number of services that implement the IDatabaseService<> interface, it provides to find and register all of them.
  • mehmetgelmedi
    mehmetgelmedi almost 4 years
    Such as this use case, how we handle? public class GenericRepository<T, U> : IGenericRepository<T> where T : class where U class I tried below code but runtime error services.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<,>));
  • Tony Ngo
    Tony Ngo almost 4 years
    You can read my blog for full source code ngohungphuc.wordpress.com/2018/05/01/…
  • Victorio Berra
    Victorio Berra over 3 years
    Can Scrutor do this? github.com/khellang/Scrutor
  • Jethro Cao
    Jethro Cao about 2 years
    Is the use of reflection then iterating over all service types to AddScoped a one time cost at application startup? My hunch says yes, but just want to confirm.