This article talks about how to register Generic interfaces in .Net Core. However I have a generic interface which has multiple arguments and am having trouble figuring out registeration and constructor injection.
My Interface has 4 arguments
public class TestImplementation
{
// Try to inject IRepository here ??????
public TestImplementation(.......)
{
...
}
}
public class Repository : IRepository<Test1, Test2, Test3, Test4>
{
...
}
public interface IRepository<T, U, V, W> where T : ITemplate1 where U : ITemplate2,...
{
...
}
If I try to inject the Interface to any class, it gives me error as the interface doesnt get resolved even using below code in other part of the code
services.GetService(typeof(IRepository<,,,>))
I tried using constructor injection but it makes compiler unhappy (Unable to resolve service for type '....Interface....' while attempting to activate xxxx) as I want to keep the Interface open. I however resolve the interface in the code
The proper way is to not inject the Repository
Service. It should just be used as a template with functionality. You then create an additional class that inherits from the Repository
class and an interface that inherits from IRepository
. That way you can assign the values of the generic values and then inject it in a neat and controlled way.
At first this pattern might seem like a bit of extra work, but it allows for custom functionality for each table repository, keeps it clear which table you are working with and allows for easy replacement for different databases. See example below:
So as you had it, create your Repository
and IRepository
interface:
public abstract class Repository<T, U, V, W> : IRepository<T, U, V, W>
{
...
}
public interface IRepository<T, U, V, W> where T : ITemplate1 where U : ITemplate2,...
{
...
}
Now create an interface for your specific table. First the interface:
public interface ISomeTableRepository : IRepository<input_1, input_2, ...> {}
Now create the class repository:
public class SomeTableRepository : Repository<input_1, input_2,...> , ISomeTableRepository {}
Now you register these the new repository that doesn't have inputs in your Startup.cs
file.
services.AddScoped<ISomeTableRepository, SomeTableRepository> ();
Now you can easily inject it without the need to add parameters:
public class TestImplementation
{
readonly ISomeTableRepository _someTable;
public TestImplementation(ISomeTableRepository someTable)
{
_someTable = someTable;
}
}
This answer seems to be getting a fair bit of views, and it is something I wrote a while ago. Below as another method for doing DPI. I still recommend the method above if you need reliability and performance, but for a quick method you can use unbound
dependency injection.
So as you had it, create your Repository
and IRepository
interface:
public abstract class Repository<T, U, V, W> : IRepository<T, U, V, W>
{
...
}
public interface IRepository<T, U, V, W> where T : ITemplate1 where U : ITemplate2,...
{
...
}
Now register the interfaces as unbound in your startup or program file:
services.AddTransient(typeof(IRepository<,,,>), typeof(Repository<,,,>));
Note that the number of inputs/variables should correlate to the number of empty spaces between the <...>
So if there is 1 input it will be <>
. If there are two: <,>
and if there are three <,,>
and so forth.