问题
I want to inject this interface to my controllers:
public interface IDatabaseService<T>
where T : class
{
T GetItem(int id);
IEnumerable<T> GetList();
void Edit(T data);
void Add(T data);
void Remove(T data);
}
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>
{
public ProjectService(DbContext context)
{
this.context = context;
}
private readonly DbContext context;
public Project GetItem(int id)
{
}
public IEnumerable<Project> GetList()
{
}
public void Edit(Project data)
{
}
public void Add(Project data)
{
}
public void Remove(Project data)
{
}
}
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?
回答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);
});
回答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
回答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
回答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
来源:https://stackoverflow.com/questions/56143613/inject-generic-interface-in-net-core