Repository pattern with generics and DI - c#

I have a base repository contract which other contracts extend, like follows
public interface IBaseRepository<T> where T : class
{
IList<T> GetContents();
}
and then there are other contracts which extend it like follows
public interface IRepository1 : IBaseRepository<MyClass1>
{
}
public interface IRepository2 : IBaseRepository<MyClass2>
{
}
I implement IRepository1 as follows
public class Repository1 : IRepository1
{
public IList<MyClass1> GetContents()
{
//some code goes here
}
}
similarly for IRepository2
public class Repository2 : IRepository2
{
public IList<MyClass2> GetContents()
{
//some code goes here
}
}
Now i have a service Service1 which implments IService like follows
public class Service1 : IService
{
}
I want to use my base repository (IBaseRepository) here in my service constructor, get an instance of this base repository and use it like so
public class Service1 : IService
{
private IBaseRepository<T> _baseRepository;
public Service1(IBaseRepository<T> baseRepository)
{
_baseRepository = baseRepository;
}
public MyMethod1()
{
var contentsOfType1 = _baseRepository<MyClass1>.GetContents();
}
public MyMethod1()
{
var contentsOfType2 = _baseRepository<MyClass2>.GetContents();
}
}
and this is what i am unable to do.
So i have a generic base repository contract with type T and have other contracts (interfaces) extending the base contract and also specifying what type T will be.
All these contracts (which extend generic base contract) have thier individual implementations.
What i want to do is in my service class, instantiate this generic base contract, and use it to infer the extending types (and hence implementations) and use the method from the base repository.
So if the base contract is
IBaseRepository<T>
and extending contract is
IRepository1 : IBaseRepository<MyClass1>
which is implemented by
Repository1 : IRepository1
i want to use this in my service class like
public class service()
{
*private IBaseRepository<T> _repo;
public service(IBaseRepository<T> repo)
{
*_repo = repo;
}
public void MyMethod()
{
*var x = _repo<MyClass1>.MethodFromIBaseRepository()
}
}
So its the *marked lines i want to achieve, which i am unable to.
I am using castle windsor for DI.
Thanks for your help guys

You should not have other repository interfaces besides your generic IRepository<T>. If you need those, you are missing an abstraction.
For instance, a common reason for people to have custom repository interfaces is because they have a custom query that some repository has, while other don't. For instance:
public interface IEmployeeRepository : IRepository<Employee>
{
Employee GetEmployeeOfTheMonth(int month);
}
The problem here is that the IEmployeeRepository is abused for a 'custom query'. Custom queries deserve their own (generic) abstraction:
// Defines a query
public interface IQuery<TResult>
{
}
// Defines the handler that will execute queries
public interface IQueryHandler<TQuery, TResult>
where TQuery : IQuery<TResult>
{
TResult Handle(TQuery query);
}
With this abstraction we can add custom queries to the system, without the need of creating IRepository<T> derivatives:
public class GetEmployeeOfTheMonthQuery : IQuery<Employee>
{
[Range(1, 12)]
public int Month { get; set; }
}
class GetEmployeeOfTheMonthHandler : IQueryHandler<GetEmployeeOfTheMonthQuery, Employee>
{
public Employee Handle(GetEmployeeOfTheMonthQuery query)
{
// todo: query the database, web service, disk, what ever.
}
}
A consumer that needs to know the employee of the month, can now simply take a dependency on IQueryHandler<GetEmployeeOfTheMonthQuery, Employee> and execute the query as follows:
var query = new GetEmployeeOfTheMonthQuery { Month = 11 };
var employee = this.employeeOfMonthHandler.Handle(query);
This might seem like overhead, but this model is very flexible, scalable, and has many interesting benefits. For instance, it is very easy to add cross-cutting concerns by wrapping handlers with decorators.
This also allows our reposities to be hidden behind one generic interface, which allows us to easily batch register them at once and add decorators to them as well.
For more in depth information, read this article: Meanwhile… on the query side of my architecture.

Not possible. The inversion of control container provide dependencies through the constructor, hence it must know in the constructor what type you want to get. So you should do this:
public class service()
{
private IBaseRepository<MyClass1> _repo;
public service(IBaseRepository<MyClass1> repo)
{
_repo = repo;
}
public void MyMethod()
{
var x = _repo.MethodFromIBaseRepository()
}
}

Related

repository pattern in ef6 with Interfaces

aLets have a simple scenario:
public interface IMember
{
string Name { get; set; }
}
public class MemberEF6Impl : IMember
{
//some annotations...
public string Name { get; set; }
}
public class MemberVMImpl : IMember
{
//some other annotations...
public string Name { get; set; }
//some functionality...
}
I have two concrete implementation of all interfaces in our programm. One implementation especially for database migration, one for our viewmodel. Now I want to realize the factory-pattern and add one more interface and two more concrete implementations of it:
public interface IRepository
{
ICollection<TModel> GetAll<TModel>() where TModel : class;
//some more functionality...
}
public class RepositoryEF6Impl : IRepository
{
protected readonly DbContext context;
public RepositoryEF6Impl(DbContext context)
{
this.context = context;
}
public ICollection<TModel> GetAll<TModel>() where TModel : class
{
return context.Set<TModel>().ToList();
}
//some more functionality...
}
Now I can use the repository straight forward as follows:
IRepository repo = new RepositoryEF6Impl(context);
repo.GetAll<MemberEF6Impl>();
So far so good. But I want to use it this way:
IRepository repo = new RepositoryEF6Impl(context);
repo.GetAll<IMember>(); //note the difference
The problem is that in the database there is no IMember, but a MemberEF6Impl.
Why I want to use it this way:
Because we have different concrete classes for databse stuff and for viewmodel, I have to create a 2nd repository as well for viewmodel, which is only a layer between the concrete VMImpl class and the EF6 repository.
public class RepositoryVMImpl : IRepository
{
protected readonly IRepository repository;
public RepositoryVMImpl(IRepository repository)
{
this.repository = repository;
}
public ICollection<TModel> GetAll<TModel>() where TModel : class
{
return repository.GetAll<TModel>();
}
}
Is there a way to achive this?
My suggestion is to use single repository, but with some method overloading for projecting the requested generic type.
Method overload:
public ICollection<TProjection> GetAll<TModel, TProjection>(Expression<Func<TModel, TProjection>> projection)
{
return context.Set<TModel>().Select(projection).ToList();
}
then you can use the method like this, which will give control over the return type.
repository.GetAll<MemberEF6Impl, IMember>(memberEF => new MemberVMImp { ... })
If you still need the EF entity model as a result type you can use your current method:
repository.GetAll<MemberEF6Impl>();
More information about EF projections: https://www.tektutorialshub.com/projection-queries-entity-framework/
Also Automapper provides such functionality - it can save you some time. You should check it out.

Dependency injection for generic class

I have a generic class and a generic interface like this:
public interface IDataService<T> where T: class
{
IEnumerable<T> GetAll();
}
public class DataService<T> : IDataService<T> where T : class
{
public IEnumerable<T> GetAll()
{
return Seed<T>.Initialize();
}
}
public static IEnumerable<T> Initialize()
{
List<T> allCalls = new List<T>();
....
return allCalls;
}
Now in my StartUp.cs I'm hooking up the class and interface
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient(typeof(IDataService<>), typeof(DataService<>));
...
}
When I try to use it in my e.g. Repository.cs its always null.
public class Repository<T> : IRepository<T> where T : class
{
private readonly IDataService<T> _dataService;
public Repository(IDataService<T> dataService)
{
_dataService = dataService;
...
}
...
}
EDIT
Here is the requested Repository Interface and class
public interface IRepository<T> where T : class
{
double GetCallPrice(T callEntity, Enum billingType);
double GetCallPriceFromIdAndBillingType(int id, Enum billingType);
}
And the Repository.cs class
public class Repository<T> : IRepository<T> where T : class
{
private readonly IDataService<T> _dataService;
private IEnumerable<T> _allCalls;
public Repository(IDataService<T> dataService)
{
_dataService = dataService;
}
public double GetCallPrice(int id)
{
_allCalls = _dataService.GetAllCalls();
...
}
...
}
services.AddTransient(typeof(IDataService<>), typeof(DataService<>));
Ideally this should not be allowed, but as method accepts type as parameter, it took it without performing any validation. As nobody expected anyone would try to use it.
The reason it is null, because typeof(IDataService<>) !== typeof(IDataService<SomeClass>)
You can check example at https://dotnetfiddle.net/8g9Bx7
That is the reason, DI resolver will never know how to resolve. Most DI containers resolve types only if type implements requested interface or has base class as requested class.
Any DI container will resolve type A for type B, only if A inherits B or A implements B.
In your case, DataService<> implements IDataService<>, but DataService<T> does not implement IDataService<>
Only way you can make it work is by calling same for every data type
services.AddTransient(typeof(IDataService<Customer>), typeof(DataService<Customer>));
services.AddTransient(typeof(IDataService<Order>), typeof(DataService<Order>));
services.AddTransient(typeof(IDataService<Message>), typeof(DataService<Message>));
OR
You can create a ServiceFactory...
interface IDataServiceFactory{
DataService<T> Get<T>();
}
class DataServiceFactory : IDataServiceFactory{
public DataService<T> Get<T>(){
//.. your own logic of creating DataService
return new DataService<T>();
}
}
And register
services.AddTransient(typeof(IDataServiceFactory), typeof(DataServiceFactory));
Microsoft's Logging extension uses open generics in their service collection configuration
services.TryAdd(ServiceDescriptor.Singleton(typeof(ILogger<>), typeof(Logger<>)));
That line lets the closed version of the logger class be injected as
public SomeService(ILogger<SomeService> logger)
{
// ...
Testing shows that, for a shared service scope, each different type of T will map to a different instance of the service, and that any valid type T that can be requested
If you want to play around with this, use this testbed: https://dotnetfiddle.net/dVDqnj
This approach assumes that behavior is not defined for specific implementations of the interface, but is more informational. If you need different implementations for IGeneric<Foo> and IGeneric<Bar>, you'll need to define each implementing service individually.

Generic registration in Windsor with UsingFactoryMethod

We currently have code that looks something like below, with a factory being injected in to a lot of classes, which then call the factory to get an instance of what they want.
public class Service
{
public Service(IFactory factory)
{
_car = factory.GetCar<Entity>();
}
}
public class Car : ICar
{
}
public interface IFactory
{
ICar<TEntity> GetCar<TEntity>();
IBoat<TEntity> GetBoat<TEntity>();
}
public class Factory : IFactory
{
ConnectionDetails _connectionDetails;
public Factory(ConnectionDetails connectionDetails)
{
_connectionDetails = connectionDetails;
}
TEntity GetCar<TEntity>()
{
var car = new Car<TEntity>(_connectionDetails);
car.Initialize();
return car;
}
}
I was hoping to be able to create a solution that would allow for request a dependency directly on the Car<TEntity> without needing to go through the factory first.
Below is an example of installing for a single TEntity, but how would I set this up to be generic?
I've tried using open generics, but I can't see how I can get the correct return type out of .UsingFactoryMethod().
I know I can get the RequestedType out of the CreationContext, but I don't see how I can use that to solve this problem.
public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<ICar<TEntity>>().UsingFactoryMethod(
kernel =>
{
var factory = kernel.Resolve<IFactory>();
return factory.GetCar<TEntity>();
}));
}
}
Personally I find that factories mixed with dependency injection can be a bit of anti-pattern, since it hides implementation/creation details somewhere other than the object graph root. In addition, when mixing the two it becomes unclear who ultimately has the responsibility for creating and maintaining objects and their lifecycles.
I'd recommend you move to allowing the container to fully handle creation details based on common base interfaces/classes.
void Main()
{
var container = new WindsorContainer();
container.Install(new Installer());
var car = container.Resolve<Car>();
car.Dump();
}
public class Service
{
private ICar<CarEntity> _car;
public Service(ICar<CarEntity> car)
{
_car = car;
}
}
public class TEntity { }
public class CarEntity : TEntity { }
public class BoatEntity : TEntity { }
public interface ICreatable { }
public interface ICar<TEntity> : ICreatable { }
public class Car : ICar<TEntity>
{
private ConnectionDetails _connectionDetails;
public Car(ConnectionDetails connectionDetails)
{
_connectionDetails = connectionDetails;
Initialize();
}
public void Initialize() {}
}
public class ConnectionDetails { }
public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<ConnectionDetails>()
.ImplementedBy<ConnectionDetails>());
container.Register(
Classes.FromAssemblyInThisApplication()
.BasedOn(typeof(ICreatable))
.WithServiceAllInterfaces()
.WithServiceSelf()
.LifestyleTransient());
}
}
You can use Castle's Typed Factory Facility to achieve this.
First you need to create an interface that Castle will implement:
public interface IFactory
{
ICar<TEntity> CreateCar<TEntity>(ConnectionDetails connectionDetails);
IBoat<TEntity> CreateBoat<TEntity>(ConnectionDetails connectionDetails);
void Release(object component); // left type as object so it can release either a boat or a car
}
With this implementation as long as your object is registered in the container with the closed generic type as its service name castle will automatically be able to find the correct object.
Then you just need to add the facility and register your factory interface:
kernel.AddFacility<TypedFactoryFacility>();
kernel.Register(Component.For<IFactory>().AsFactory());
The article I linked at the top also covers the naming semantics of the methods in the interface as some words are given special meaning.

Design Patterns: Abstract Factory and Generic Repository

Here is my design of domain model and generic repository
public interface IEntity
{
long Id { get; }
}
public interface IRepository<T> where T : class, IEntity, new()
{
void Save(T entity);
void Delete(long id);
T Get(long id);
IEnumerable<T> GetAll();
}
public interface IUserRepository : IRepository<User>
{
User Login(string username, string password);
}
public class User : IEntity
{
// Implementation of User
}
public abstract class BaseRepository<T> : IRepository<T> where T : class, IEntity, new()
{
// Implementation of IRepository
}
public class UserRepository : BaseRepository<User>, IUserRepository
{
// Implementation of IUserRepository
// Override BaseRepository if required
}
When I want to instantiate a repository instance I use a factory which implements following interface
public interface IRepositoryFactory
{
R CreateRepository<R, T>()
where R : IRepository<T>
where T : class, IEntity, new();
}
And use the factory object as below
1. IRepositoryFactory factory = CreateFactory();
2. IUserRepository repository = factory.CreateRepository<IUserRepository, User>();
3. User user = repository.Login("user", "1234");
My problem is in the second line. I would like to use my factory like.
// Without specifying the User type parameter
factory.CreateRepository<IUserRepository>()
Since my IRepository interface has contstraint on type of entity my factory uses same constraint to satisfy IRepository requirement.
Is there any way to isolate this parameter from client?
I agree with the others that you would benefit from looking at a DI/IoC framework like Ninject.
So this answer is not a suggestion to not follow the other advices. But still, there are ways for you to solve your problem at a lower level. This code is not tested very well, but you could do something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using NUnit.Framework;
namespace TestConsole1
{
public interface IEntity
{
long Id { get; }
}
public interface IRepository<T> where T : class, IEntity, new()
{
void Save(T entity);
void Delete(long id);
T Get(long id);
IEnumerable<T> GetAll();
}
public interface IUserRepository : IRepository<User>
{
User Login(string username, string password);
}
public class User : IEntity
{
// Implementation of User
public long Id
{
get { return 42; }
}
}
public abstract class BaseRepository<T> : IRepository<T> where T : class, IEntity, new()
{
// Implementation of IRepository
public void Save(T entity)
{
throw new NotImplementedException();
}
public void Delete(long id)
{
throw new NotImplementedException();
}
public T Get(long id)
{
throw new NotImplementedException();
}
public IEnumerable<T> GetAll()
{
throw new NotImplementedException();
}
}
public class UserRepository : BaseRepository<User>, IUserRepository
{
// Implementation of IUserRepository
// Override BaseRepository if required
public User Login(string username, string password)
{
return new User();
}
}
class Factory
{
public T CreateRepository<T>() where T : class
{
//TODO: Implement some caching to avoid overhead of repeated reflection
var abstractType = typeof(T);
var types = AppDomain.CurrentDomain.GetAssemblies().ToList()
.SelectMany(s => s.GetTypes())
.Where(p => p.IsClass &&
!p.IsAbstract &&
abstractType.IsAssignableFrom(p));
var concreteType = types.FirstOrDefault();
if (concreteType == null)
throw new InvalidOperationException(String.Format("No implementation of {0} was found", abstractType));
return Activator.CreateInstance(concreteType) as T;
}
}
class Program
{
static void Main(string[] args)
{
var factory = new Factory();
var userRepo = factory.CreateRepository<IUserRepository>();
Console.WriteLine(userRepo.GetType());
User user = userRepo.Login("name", "pwd");
Console.WriteLine(user.Id);
Console.ReadKey();
}
}
}
As this code reveals, a central point is that you will need to handle the coupling between your interface and the concrete class, for example between your IUserRepository and your UserRepository. If you do not handle this relation in a direct way via a mapper or similar you can implement a more automatic way like the one that is illustrated in the code.
However, if you use something like Ninject instead to handle this for you, it will be a better investment of your time as you will most likely find that the complexity of your factory class will grow significantly over time.
Br. Morten
There are 3 problems with your code:
First is IEntity. Having single type of ID is against DDD, because in DDD, identity of object is given by domain and it can be anything from string, int, guid to complex type.
Second is generic repository with IRepository, which again, is highly useless, because you will rarely pass this interface and mostly will pass interface for repository for concrete entity.
Third thing is that in DDD repositories should exist only for aggregate roots, which is not reflected in your design.
If you fix this, you will find out, that implementation of interface of repository for specific entity can easily be suplied by DI framework.

MVC generic repository common dataColumn

I have a generic repository that I use for common things such as FetchAllData, GetbyID and so on... Anyway, I want to include a Deactivate(T Entity) method so that instead of deleting data I will just turn their status off so the user will not see the data, but I can see it whenever I need. Basically, something similar to:
public interface IGenericRepository<T> where T : class {
...somecode
}
public class GenericRepository<T> : IGenericRepository<T> where T : class {
public T GetbyID(int id) { ... }
public void Deactivate(T entity) {
entity.stat = 0; // I know that this stat is common in all tables. However,
// my problem is that I don't know how to make appear stat
// in IntelliSense.
}
}
I know that this can be done, but I how do I do it?
Declare a interface:
public interface IDeactivatable {
int stats { get; set; }
}
Then your entities must derive from IDeactivatable.
Tip: You can add a generic type constraint too:
[...] IGenericRepository<T> where T : class, IDeactivatable [...]

Categories

Resources