18

Working on a read-only api service and making use of generics to package the operation into convention based process.

Repository interface:

public interface IRepository<TIdType,TEntityType> where TEntityType:class {
   Task<EntityMetadata<TIdType>> GetMetaAsync();
}

Repository implementation:

public class Repository<TIdType,TEntityType> : IRepository<TIdType,TEntityType> where TEntityType:class {
   public Repository(string connectionString) { // initialization }
   public async Tas<EntityMetadata<TIdType>> GetMetaAsync() { // implementation   }
}

In Startup.cs -> ConfigureServices :

services.AddSingleton<IRepository<int, Employee>> ( p=> new Repository<int, Employee>(connectionString));
services.AddSingleton<IRepository<int, Department>> ( p=> new Repository<int, Department>(connectionString));
// and so on

Controller:

public class EmployeeController : Controller {
   public EmployeeController(IRepository<int,Employee> repo) {//stuff}
}

I am currently repeating the repository implmentation for all types of entity types in the ConfigureServices. Is there a way to make this generic too?

services.AddSingleton<IRepository<TIdType, TEntityType>> ( p=> new Repository<TIdType, TEntityType>(connectionString));

so in the controller constructor call can automatically get the relevant repository?

Update 1: Not a duplicate:

  1. The repository implementation does not have default constructor
  2. Because it does not have default constructor, I cannot provide the solution given in the linked question.
  3. When trying services.AddScoped(typeof(IRepository<>), ...) I am getting error Using the generic type 'IRepostiory<TIdType,TEntityType>' requires 2 type arguments
7
  • stackoverflow.com/questions/33566075/… Commented Mar 29, 2017 at 8:18
  • 3
    technically it is a duplicate. But when you have 2 parameters you have to use typeof(IRepository<,>) instead of typeof(IRepository<>) because it has two generic parameters Commented Mar 29, 2017 at 8:52
  • @Tseng And could you also mention how to initiate the constructor of the repository? Maybe add it as an answer and I can mark it as complete. Commented Mar 29, 2017 at 10:02
  • What do you mean with initiate? Any parameters in the constructor of the concrete implementation (i.e. GenericRepository<TIdType,TEntityType> will be resolved by the IoC container. In the services which require it, you request it via IRepository<int,User> Commented Mar 29, 2017 at 10:25
  • @Tseng kindly go through the full question Commented Mar 29, 2017 at 10:29

1 Answer 1

39

Since this question is still not properly marked as duplicate: The way to register a Generic class:

services.AddScoped(typeof(IRepository<,>), typeof(Repository<,>));

now you can resolve it in the following way:

serviceProvider.GetService(typeof(IRepository<A,B>));
// or: with extensionmethod
serviceProvider.GetService<IRepository<A,B>>();
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks for answering, but to clarify the repository does not have default constructor as it needs to be initiated with the connection string. Currently I am registering the dependency as services.AddSingleton<IRepository<int, Department>> ( p=> new Repository<int, Department>(connectionString)); but how can I pass the connection string when using services.AddScoped(typeof(IRepository<,>), typeof(Repository<,>));
@Vijay Use the IOptions<MyConnectStringOptions> Pattern, this way you can inject a typed class/options, strings wont work as you say you yave to manualy define strings in constructor
do you mean that my repository will have a dependency on a MyConnectionStringOptions type, which means I register that in the DI with an instance populated with proper connection strings. So that the constructor of the repository can use GetService the connection string options object and proceed?
Exactly, i would call it DatabaseOptions though and also add Timeout and maybe some other usefull optoins and make it populate from Appsettings using the IOptions pattern and the ConfigurationBuilder
@Vijay What about the bit about your registrations being singletons? Or is that not relevant to you anymore? Unless this answer is somehow creating a singleton in a way that I can't see...
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.