c# interface inheritance - not recognizing base interface methods - c#

I'm creating an ASP layered web application and I have the following structure:
IService<T>
public interface IService<T> {
IEnumerable<T> GetAll();
void Add(T entity);
void Delete(T entity);
Service<T>
public class Service<T> where T : class {
private IRepository<T> _repository;
public Service(IRepository<T> repo) {
this._repository = repo;
}
public IEnumerable<T> GetAll() {
return _repository.GetAll();
}
etc
And then I also have some 'custom services':
ICategoryService
public interface ICategoryService : IService<Category> {
IEnumerable<Category> GetProductCategories(int productId);
}
CategoryService
public class CategoryService : Service<Category>, ICategoryService {
private IRepository<Category> _repository;
public CategoryService(IRepository<Category> repo) : base(repo) {
this._repository = repo;
}
public IEnumerable<Category> GetProductCategories(int productId) {
// implementation
}
Controller:
public class ProductController : Controller {
private ICategoryService _cservice;
public ProductController(ICategoryService cservice) {
this._cservice = cservice;
}
ยด
// other methods
public ActionResult Categories() {
IEnumerable<Category> categories = _cservice.GetAll(); // doesn't work
}
I'm trying to access the .GetAll() method in my controller, which was defined in IService and implemented in Service, but I'm getting a 'ICategoryService contains no definition for GetAll' error and I have no idea why.
I can access the .GetAll() method from my CategoryService, so I don't know why I can't access it from a CategoryService instance (via dependency injection).

You might have made a typo when posting your code, but, it seems that Service<T> doesn't implement IService<T> change the class's implementation to:
public class Service<T> : IService<T>
where T : class
{
private IRepository<T> _repository;
public Service(IRepository<T> repo) {
this._repository = repo;
}
public IEnumerable<T> GetAll() {
return _repository.GetAll();
}
I would also move the where T : class constraint from the class to interface.

Related

LightInject register generic with parameters?

I have Interface IRepository and Class Repository with parameter constructor which Implement IRepository. Both Class and Interface are generic. I want to pass this parameter while registering. The code is as follows:
public interface IRepository<T> where T : class, new()
{
public Task<int> InsertAsync(T entity);
}
public class Repository<T> : IRepository<T> where T : class, new()
{
public MobileServiceClient MobileService { get; set; }
public Repository(MobileServiceClient mobileService)
{
MobileService = mobileService;
}
public async Task<int> InsertAsync(T entity)
{
var table = MobileService.GetSyncTable<T>();
await table.InsertAsync(entity);
return 1;
}
}
I did generic class registration like this
Container.Register(typeof(IRepository<>), typeof(Repository<>));
I am not finding way to pass parameter while registering.

C# : Extending Generic class

partial class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
}
My generic repository implements a common set of methods for TEntity like
public TEntity Get(int id)
{
return _context.Set<TEntity>()
.Find(id);
}
public TEntity Get(Expression<Func<TEntity, bool>> predicate)
{
return _context.Set<TEntity>()
}
which I can access like
Repository<User>().Get();
Many repositories does the same set of operation, so it is beneficial but now I want to extend Repository<User> to support some additional behavior.
partial class Repository<User> : IRepository<User>
{
public user DoMagicFunction()
{
}
}
so that I can use the repository like
Repository<User>().DoMagicFunction();
how can I extend the same generic class for Some Tentity to extend new behaviour instead of modifying it.
I could have done the same like creating another UserRepository to support new feature, but the accessor would become
UserRepository.DoMagicFunction();
but I want it to be like
Repository<User>().DoMagicFunction();
You can use an extension method:
public static class ExtensionMethods {
public static User DoMagicFunction(this Repository<User> repository) {
// some magic
return null; //or another user
}
}
This will thus add the function in a syntactically nice way to Repository<User> objects.
In case you want to support it not only for Users, but for subclasses of Users as well, you can make the function generic:
public static class ExtensionMethods {
public static TEntity DoMagicFunction<TEntity>(this Repository<TEntity> repository)
where TEntity : User {
// some magic
return null; //or another TEntity
}
}
C# has a language feature called Extension Methods, you probably are using them from the .NET framework without knowing (e.g. the linq extensions methods). It's common to extend your classes or even your interfaces with extension methods without breaking the functionality of your code. Here is an example for your case.
Suppose you have a generic IRepository interface:
public interface IRepository<TEntity> where TEntity : class, IEntity
{
IQueryable<TEntity> Entities { get; }
}
This interface adheres to the SOLID principles, especially the O and I principle.
Now suppose IEntity looks like this:
public interface IEntity
{
int Id { get; }
}
Now you could perfectly imagine an often reusable extension method like this:
public static class RepositoryExtensions
{
// similar to your MagicFunction
public static TEntity GetById<TEntity>(this IRepository<TEntity> repository, int id)
where TEntity : class, IEntity
{
return repository.Entities.Single(entity => entity.Id == id);
}
}
In a similar manner you could also extend your Repository class
public static class RepositoryExtensions
{
public static TEntity GenericMagicFunction<TEntity>(this Repository<TEntity> repository)
{
//do some stuff
}
}
You can now consume that like this:
var repository = new Repository<User>();
var user = repository.GenericMagicFunction();
You could also limit your extension method:
public static class RepositoryExtensions
{
public static User DoMagicFunction(this Repository<User> repository)
{
//do some stuff
}
}
But doing this will defeat it's purpose, you could rather just implement this in the Repository<User> class.
If your system and architecture uses Dependency Injection, you're probably injecting an IRepository<User> to your consuming classes. So the first or second extension method examples I've provided would make the most sense.
If you want to extend any repository you can do it like this.
public static class RepositoryExtension
{
public static void MagicMethod<TEntity>(this IRepository<TEntity> repo) where TEntity: class
{
....
}
}
For a specific repository (eg User repository) you can use a similar process
public static class RepositoryExtension
{
public static void MagicMethod(this IRepository<User> repo)
{
....
}
}
Extension methods are not the way to go, because the code that implements the method can only access public/internal members of the class they extend and you are likely to want your repository's DataContext to be private.
In my opinion, your approach needs to be changed slightly.
What if in the future you want to add a Delete method to your generic repository, but you have some entities that should never be deleted? You'll end up with an instance of a repository for something like PurchaseOrder that you'll either have to remember to never call delete on or you will have to create a descendant of Repository<T> that throws an InvalidOperationException if called. Both of which are poor implementations.
Instead, you should delete your IRepository<T> interface completely. Keep your Repository<T> class, but explicitly define a repository interface for every entity that only has the methods you require.
public class Repository<TKey, TEntity>......
{
public TEntity Get<TEntity>(TKey key)....
public void Delete(TEntity instance)....
...etc...
}
public interface IPurchaseOrderRepository {
PurchaseOrder Get(int orderNumber);
// Note: No delete is exposed
}
MyDependencyInjection.Register<IPurchaseOrderRepository, Repository<PurchaseOrder, int>>();
When you need additional methods on your repository you add them to your IPurchaseOrderRepository and create a descendant of Repository<T>
public interface IPurchaseOrderRepository {
PurchaseOrder Get(int orderNumber);
void DoSomethingElse(int orderNumber);
}
public class PurchaseOrderRepository: Repository<PurchaseOrder, int> {
public void DoSomethingElse(int orderNumber) {.......}
}
MyDependencyInjection.Register<IPurchaseOrderRepository, PurchaseOrderRepository>();
Extension method is a best choice for this case.
Note: I have not checked but you should check Dependency Injection still works well as normal.
You can use below code for testing:
public class Employee
{
}
public class User
{
}
public interface IRepo<TEntity> where TEntity : class
{
TEntity Get(int id);
DbSet<TEntity> Get(Expression<Func<TEntity, bool>> predicate);
DbContext GetContext();
}
public class Repo<TEntity> : IRepo<TEntity> where TEntity : class
{
DbContext _context;
public TEntity Get(int id)
{
return _context.Set<TEntity>()
.Find(id);
}
public DbSet<TEntity> Get(Expression<Func<TEntity, bool>> predicate)
{
return _context.Set<TEntity>();
}
public DbContext GetContext()
{
return _context;
}
}
public static class RepoExtensions
{
public static ChangeTracker DoMagic(this Repo<User> userRepo)
{
return userRepo.GetContext().ChangeTracker;
}
}
public static class Test
{
public static void DoTest()
{
Repo<User> repoUser = new Repo<User>();
repoUser.DoMagic();
Repo<Employee> repoEmployee = new Repo<Employee>();
//repoEmployee.DoMagic();
}
}

Generic UnitOfWork and Repository

I'm refactoring my code and I started by removing a reference to Entity Framework in my service layer. This layer uses unit of work and repositories (through interfaces) located in my DAL layer.
Now I encountered a problem because my base repository class looks like this:
public interface IDatabaseFactory<C> : IDisposable
{
C Get();
void Set(string connectionString);
}
public abstract class Repository<C, T> : IRepository<T>
where C : DbContext, IBaseContext
where T : class, IEntity
{
protected readonly IDbSet<T> dbset;
private C dataContext;
protected Repository(IDatabaseFactory<C> databaseFactory)
{
this.DatabaseFactory = databaseFactory;
this.dbset = DataContext.Set<T>();
}
protected IDatabaseFactory<C> DatabaseFactory
{
get;
private set;
}
protected C DataContext
{
get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
}
public virtual void Add(T entity)
{
dbset.Add(entity);
}
//etc...
}
I obviously need the DbContext constraint on type C. However, if I do so, I get errors on dataContext because it cannot resolve C in DbContext.
How can I overcome this problem?
EDIT
A typical repository looks like this:
public interface ICustomerTypeRepository : IRepository<CustomerType> { }
public class CustomerTypeRepository : Repository<IBaseContext, CustomerType>, ICustomerTypeRepository
{
public CustomerTypeRepository(IDatabaseFactory<IBaseContext> databaseFactory)
: base(databaseFactory) { }
}
After the changes suggested below, I still get the same errors:
The type 'IBaseContext' cannot be used as type parameter 'TContext' in the generic type or method 'Repository'. There is no implicit reference conversion from 'IBaseContext' to 'System.Data.Entity.DbContext'.
To fix compilation error, you have to put appropriate constraints to your generic types (I've replaced C to TContext for readability):
interface IBaseContext { }
interface IDatabaseFactory<TContext> : IDisposable
where TContext : DbContext
{
TContext Get();
void Set(string connectionString);
}
interface IEntity { }
interface IRepository<T>
where T : class, IEntity
{ }
abstract class Repository<TContext, T> : IRepository<T>
where TContext : DbContext, IBaseContext
where T : class, IEntity
{
protected readonly IDbSet<T> dbset;
private TContext dataContext;
protected Repository(IDatabaseFactory<TContext> databaseFactory)
{
this.DatabaseFactory = databaseFactory;
this.dbset = DataContext.Set<T>();
}
protected IDatabaseFactory<TContext> DatabaseFactory { get; private set; }
protected TContext DataContext
{
get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
}
public virtual void Add(T entity)
{
dbset.Add(entity);
}
//etc...
}
But from the point of architecture, looks like that holding a reference to DbContext in repository is superfluous. Of course, it is hard to propose better solutiuon without knowledge about all of your types.
For remove DbContext from your code you need change IDatabaseFactory like this:
public interface IDatabaseFactory : IDisposable
{
T Set<T>() where T : IEntity;
}
Then you can change Repository
public abstract class Repository<T> : IRepository<T>
where T : class, IEntity
{
protected readonly IDbSet<T> dbset;
protected Repository(IDatabaseFactory databaseFactory)
{
this.dbset = databaseFactory.Set<T>();
}
// other code
}
Implementation of IDatabaseFactory:
public class DatabaseFactory : IDatabaseFactory
{
private readonly DbContext _context;
public DatabaseFactory(DbContext context)
{
_context = context;
}
public T Set<T>() where T : Entity
{
return _context.Set<T>();
}
}

Implementing a generic type in repository

Im not sure if what I'd like to do is possible since I haven't found anything on google and after about 30minutes of intensive search I decided to ask directly.
I have definded a simple interface for my repository
public interface IRepository<TEntity> : IDisposable
{
TEntity GetById(object id);
List<TEntity> GetAll();
}
Now I want to implement my first repository and it works like this
public class ContentRepository : IRepository<ContentPages>
{
private readonly Context _db = new Context();
public ContentPages GetById(object id)
{
var result = _db.ContentPages.Find(id);
return result;
}
public List<ContentPages> GetAll()
{
return _db.ContentPages.ToList();
}
public void Dispose()
{
_db.Dispose();
}
}
This works fine but when I inject my repository to my mvc Controller it takes an IRepository<ContentPages> as parameter type and I just want it to take an IRepository.
I tried to move the generic type to the functions itself like this
public interface IRepository : IDisposable
{
TEntity GetById<TEntity>(object id);
List<TEntity> GetAll<TEntity>();
}
}
When I do this I don't know how to define my generic type TEntity in the implementation
So in conclusion I want my use the interface without speficing a type so it gets the type from the actual object like this
public constructor1(IRepository ContentRepository){}
the next controller gets this constructor
public constructor2(IRepository BlogRepository){}
and so on
I hope I could describe my problem close enough for u guys to understand :)
Within the concrete implementation of IRepository Class you can define the type of the TEntity as follows.
public TEntity GetById<TEntity>(object id) where TEntity:class
{
// Implimetation
}
But in here according to repository pattern better to use as follows.
public interface IRepository<TEntity>: IDisposable where TEntity : class
try such variant:
public interface IRepository<TEntity> where TEntity : class
{
TEntity Find(params object[] keyValues);
// ...
}
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
private readonly IDbSet<TEntity> _dbSet;
public Repository(IDbContext context)
{
_dbSet = context.Set<TEntity>();
}
public virtual TEntity Find(params object[] keyValues)
{
return _dbSet.Find(keyValues);
}
// ...
}
Example of usage:
IRepository<ApplicationUser> repository = new Repository<ApplicationUser>(new ApplicationDbContext());
ApplicationUser applicationUser = repository.Find("key");
Also, there is a better solution - you can use pattern UnitOfWork. Check this implementation on codeplex. It is really cool.
Example:
public class DatabasesController : Controller
{
private UnitOfWork _unitOfWork;
private WebContext _context;
public DatabasesController()
{
_context = new WebContext();
_unitOfWork = new UnitOfWork(_context);
}
//
// GET: /Databases/
public ViewResult Index()
{
List<Database> databases =
_unitOfWork
.Repository<Database>()
.Query()
.Include(database => database.FileEntitiesInfo)
.Get()
.ToList();
_unitOfWork.Save();
return View(databases);
}
}

A c# Generics question involving Controllers and Repositories

I have a base repository class which contains all the common repository methods (as generic):
public abstract class BaseRepository<T, IdType> : IBaseRepository<T, IdType>
My repositories from this base e.g.:
public class UserRepository : BaseRepository<User, int>, IUserRepository
I also have a base controller class containing common actions, and inherit from this in controllers. The repository is injected into this by DI. E.g.
public class UserController : BaseController<User>
{
private readonly IUserRepository userRepository;
public UserController (IUserRepository userRepository)
{
this.userRepository= userRepository;
}
My question is this: The base controller needs to be able to access the repository methods that are defined in the base repository. However I'm passing in via DI a different repository type for each controller (even though they all inherrit from the base repository). How can the base controller somehow access the repository that is passed in (regardless of what type it is), so that it can access the common base methods?
It all your repositories will be derived from IBaseRepository<T,IdType>, then have:
interface IUserRepository : IBaseRepository<User,int> {...}
Now any reference to a IUserRepository will know about the IBaseRepository<> members, without having to mention concrete types like the UserRepository class or BaseRepository<> class.
You can hold a reference for BaseReposiroty in BaseController
public class BaseController <T, IdType>
{
...
...
protected BaseRepository<T, IdType> Reposirory
{
{ get; set; }
}
...
...
}
Here's one way to do it..
public abstract class BaseController<TEntity, TRepository, TIdType>
where TEntity : class, new()
where TRepository : IBaseRepository<TEntity, TIdType>
{
protected TRepository Repository = RepositiryFactory.GetRepository<TEntity, TRepository>();
public IList<TEntity> GetAll()
{
return Repository.GetAll().ToList();
}
public IList<TEntity> GetAll(string sortExpression)
{
return Repository.GetAll(sortExpression).ToList();
}
public int GetCount()
{
return Repository.GetAll().Count();
}
public IList<TEntity> GetAll(int startRowIndex, int maximumRows)
{
var results = Repository.GetAll().Skip(startRowIndex).Take(maximumRows);
return results.ToList();
}
public IList<TEntity> GetAll(string sortExpression, int startRowIndex, int maximumRows)
{
var results = Repository.GetAll(sortExpression).Skip(startRowIndex).Take(maximumRows);
return results.ToList();
}
}

Categories