Inject generic interface in .NET Core
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
michasaucer
Updated on July 09, 2022Comments
-
michasaucer 11 months
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 likeProjectController
,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 about 4 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 about 4 yearsI wanted to work only on
DbSet
withProjects
in my mind, so how it work in "real life" scenerios? Its better to deal with oneIDatabaseService
andDatabaseService
if each one controller? I thinkProjectController
dont need to have (for example) reference toTasks
-
Voodoo about 4 yearsThanks for the comments. I have removed the wrong example.
-
michasaucer about 4 yearsThanks, but as you can see in my quesion, i wan to have classes like
TaskService : IDatabaseService<Task>
andProjectService : IDatabaseService<Project>
. I dobt have 'DatabaseService' class -
michasaucer about 4 yearsCould you provide more complex explenation about second paragraph?
-
levent about 4 yearsIf you have a large number of services that implement the IDatabaseService<> interface, it provides to find and register all of them.
-
mehmetgelmedi about 3 yearsSuch 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 about 3 yearsYou can read my blog for full source code ngohungphuc.wordpress.com/2018/05/01/…
-
Victorio Berra over 2 yearsCan Scrutor do this? github.com/khellang/Scrutor
-
Jethro Cao about 1 yearIs 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.