Inject different implementations that have same interface in multiple constructor parameters - c#

My goal is to create an object that contains different implementations of an interface and at runtime select the implementation to use. I'm using the Dependency injection in ASP.NET Core.
Code:
public interface IStateRepository : IDbReadRepository<IState> { }
public interface IDbReadRepository<T> : IBaseRepository
{
IReadOnlyList<T> GetAll();
}
public interface IBaseRepository
{
IUserContext UserContext { get; set; }
}
namespace MvcOpinionatedTemplate.Repositories.Dapper
{
public class StateRepository : BaseDbRepository, IStateRepository
{
public StateRepository(IUserContext userContext, IDbConnection dbConnection) : base(userContext, dbConnection) { }
public IReadOnlyList<IState> GetAll()
{
return _dbConnection.Query<State>("SELECT * FROM State").ToList();
}
}
}
namespace Template.Repositories.Local
{
public class StateRepository : BaseRepository, IStateRepository
{
public StateRepository(IUserContext userContext) : base(userContext) { }
public IReadOnlyList<IState> GetAll()
{
var filePath = Path.Combine(AppContext.BaseDirectory, #"Local\json\states.json");
return JsonConvert.DeserializeObject<List<State>>(File.ReadAllText(filePath));
}
}
namespace MvcOpinionatedTemplate.Repositories.Collections
{
public class StateRepositories
{
public IStateRepository Local { get; }
public IStateRepository SqlServer { get; }
public StateRepositories(IStateRepository local, IStateRepository sqlServer)
{
Local = local;
SqlServer = sqlServer;
}
}
}
What I'd like to do is set in the Startup.ConfigureServices():
services.AddTransient<StateRepositories, XXXXX>
I tried this:
services.AddTransient<StateRepositories>(s => new StateRepositories(new Repositories.Local.StateRepository(--UserContext--), new Repositories.Dapper.StateRepository(-UserContext--)));
The problem is how to have DI populate UserContext. I have it defined Startup.ConfigureServices():
services.AddScoped<IUserContext, UserContext>();
How do have DI populate UserContext for the StateRepositories implementations? Or is there a better approach to achieve my goal?

You can register your IStateRepository separately and then inject IEnumerable<IStateRepository> which injects all implementations of IStateRepository.
public interface IStateRepository
{
}
public class LocalRepository : IStateRepository
{
}
public class DapperRepository : IStateRepository
{
}
services.AddTransient<IStateRepository, LocalRepository>()
.AddTransient<IStateRepository, DapperRepository>()
.AddTransient<StateRepositories>();
public class StateRepositories
{
public IStateRepository Local { get; }
public IStateRepository SqlServer { get; }
public StateRepositories(IEnumerable<IStateRepository> repositories)
{
Local = repositories.OfType<LocalRepository>().FirstOrDefault();
SqlServer = repositories.OfType<DapperRepository>().FirstOrDefault();
}
}

Related

Extract Reusable Code into Abstract Base Class with Generic Parameters

I am trying to achieve a design in c# like below.
void Main()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddScoped(typeof(RedisRepository<>));
serviceCollection.AddScoped(typeof(CommitterBase<IDto>), typeof(ACommitter));
serviceCollection.AddScoped(typeof(CommitterBase<IDto>), typeof(BCommitter));
serviceCollection.AddScoped<Client>();
var services = serviceCollection.BuildServiceProvider();
var client = services.GetRequiredService<Client>();
client.Dump();
}
public class RedisRepository<T> where T: IDto
{
public void Add(T dto)
{
Console.WriteLine("Added data");
}
}
public interface IDto
{
}
public class ADto: IDto
{
}
public class BDto : IDto
{
}
and :
public abstract class CommitterBase<T> where T: IDto
{
public CommitterBase(RedisRepository<T> repo)
{ }
public void Commit()
{
var dto = GenerateDto();
//do something with dto here
}
protected abstract T GenerateDto();
}
and its implementations:
public class ACommitter : CommitterBase<ADto>
{
public ACommitter(RedisRepository<ADto> repo): base(repo)
{ }
protected override ADto GenerateDto()
{
return new ADto();
}
}
public class BCommitter : CommitterBase<BDto>
{
public BCommitter(RedisRepository<BDto> repo) : base(repo)
{
}
protected override BDto GenerateDto()
{
return new BDto();
}
}
public class Client
{
public Client(IEnumerable<CommitterBase<IDto>> committers)
{ }
}
error that I get
Implementation type 'BCommitter' can't be converted to
service type 'UserQuery+CommitterBase`1[IDto]'
I understand from this stackoverflow post that this error is expected. Just wondering how to achieve similar effect without encountering the error. My aim is to extract reusable code into an Abstract Base Class and let the implementations do bare minimum.
Thanks in advance!
Interface cannot be instantiated and IDto is interface. So you can register specific implementation to your interface.
I little bit refactored code to use generic parameters.
This is yor base abstract class:
public abstract class CommitterBase<T> where T : IDto
{
public CommitterBase(RedisRepository<T> repo)
{ }
public void Commit()
{
var dto = GenerateDto();
//do something with dto here
}
protected abstract T GenerateDto();
}
And its concrete implementations such as ACommitter:
public class ACommitter<T> : CommitterBase<T> where T : IDto, new()
{
public ACommitter(RedisRepository<T> repo) : base(repo)
{ }
protected override T GenerateDto()
{
return new T();
}
}
and BCommitter:
public class BCommitter<T> : CommitterBase<T> where T: IDto, new()
{
public T FooBar { get; set; }
public BCommitter(RedisRepository<T> repo) : base(repo)
{
}
protected override T GenerateDto()
{
return new T();
}
}
and RedisRepository:
public class RedisRepository<T> where T : IDto
{
public void Add(T dto)
{
Console.WriteLine("Added data");
}
}
and Client class:
public class Client<T> where T : IDto, new()
{
public CommitterBase<T> CommitterBaseProperty { get; set; }
public Client(CommitterBase<T> committer) // if you want all instances of committers,
// then you need to create a factory
// and inject it through DI
{
CommitterBaseProperty = committer;
}
}
And you can call it like this:
static void Main(string[] args)
{
ServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddScoped<RedisRepository<ADto>>();
serviceCollection.AddScoped<RedisRepository<BDto>>();
serviceCollection.AddScoped<CommitterBase<ADto>, ACommitter<ADto>>();
serviceCollection.AddScoped<CommitterBase<BDto>, BCommitter<BDto>>();
serviceCollection.AddScoped<Client<ADto>>();
ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
CommitterBase<ADto> committerBase = serviceProvider.GetRequiredService<CommitterBase<ADto>>();
CommitterBase<BDto> committerBase_B =
serviceProvider.GetRequiredService<CommitterBase<BDto>>();
committerBase.Commit();
Client<ADto> client = serviceProvider.GetRequiredService<Client<ADto>>();
}

Object Reference Not Set to an Instance of an Object at Repository Layer

I am receiving null exception error on my framework. I have tried to apply Repository and Unit of Work design patterns in my application. What I am trying to do is simply retreiving user titles from my data base with GetAll() method.
Here is my repository class:
public class Repository<T> : IRepository<T> where T : class
{
protected readonly DbContext Context;
public Repository(DbContext context)
{
this.Context = context;
}
public T Get(int id)
{
return Context.Set<T>().Find(id);
}
public IEnumerable<T> GetAll()
{
return Context.Set<T>().ToList();
}
public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
{
return Context.Set<T>().Where(predicate);
}
public void Add(T entity)
{
Context.Set<T>().Add(entity);
}
public void AddRange(IEnumerable<T> entityList)
{
Context.Set<T>().AddRange(entityList);
}
public void Remove(T entity)
{
Context.Set<T>().Remove(entity);
}
public void RemoveRange(IEnumerable<T> entityList)
{
Context.Set<T>().RemoveRange(entityList);
}
}
This is IUserTitlesRepository:
public interface IUserTitlesRepository : IRepository<UserTitles>
{
}
And, the class where above interface implemented:
public UserTitlesRepository(XaPaDataContext context) : base(context)
{
}
public XaPaDataContext XaPaDataContext
{
get { return Context as XaPaDataContext; }
}
Before coming to Controller layer, I have two more layers, which are Operation and Manager layers. And, I think I have messed up on that part (on Base Manager class as shown below).
This is operation layer:
public class UserTitlesOperations
{
private readonly IUnitOfWork _uow;
public UserTitlesOperations(IUnitOfWork uow)
{
_uow = uow;
}
public List<UserTitles> GetAllUserTitles()
{
try
{
List<UserTitles> userTitleList = _uow.UserTitles.GetAll().ToList();
_uow.Complete();
return userTitleList;
}
catch (Exception ex)
{
throw new Exception(ex.ToString());
}
}
}
Below is the BaseManager class which gives inheritance to all manager classes.
public abstract class BaseManager
{
private IUnitOfWork _iUow;
private readonly XaPaDataContext _context;
public IUnitOfWork IUOW
{
get
{
if (_iUow == null)
{
_iUow = new XaPaUnitOfWork(_context);
}
return _iUow;
}
}
}
This is the manager class:
public class UserTitlesManager : BaseManager
{
private readonly UserTitlesOperations _userTitlesOperations;
public UserTitlesManager()
{
_userTitlesOperations = new UserTitlesOperations(base.IUOW);
}
public List<UserTitlesWM> GetAllUserTitles()
{
try
{
return UserTitlesMapping.MaptoWM(_userTitlesOperations.GetAllUserTitles());
}
catch (Exception ex)
{
throw new Exception(ex.ToString());
}
}
}
Finally, this is my API Controller:
[Route("api/LoginRequest")]
public class TitlesController : BaseController
{
UserTitlesManager _userTitlesManager;
public LoginController()
{
_userTitlesManager = new UserTitlesManager();
}
[Route("RetreiveTitles")]
public HttpResponseMessage GetTitles()
{
try
{
return Request.CreateResponse(HttpStatusCode.OK, _userTitlesManager.GetAllUserTitles());
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex.ToString());
}
}
}
By the way BaseController is just another API controller which gives inheritance to all other API controllers, and houses a method which is used by all the other controllers.
So, I'm still trying to sharpen my self on this design patterns and would be glad if anyone could show my mistake on BaseManager class. As I said, I suppose the problem is caused by that private readonly XaPaDataContext _context; line. On the other hand,I can't figure out how to corrrect it as my operation classes' constructors are asking for IUnitOfWork.
Thank you in advance!
EDIT:
Just realized that I forgot to share my Unit of Work class:
public class XaPaUnitOfWork : IUnitOfWork
{
private readonly XaPaDataContext _context;
public XaPaUnitOfWork(XaPaDataContext context)
{
_context = context;
Categories = new CategoriesRepository(_context);
OrderDetails = new OrderDetailsRepository(_context);
Orders = new OrdersRepository(_context);
ProductImages = new ProductImagesRepository(_context);
Products = new ProductsRepository(_context);
Users = new UsersRepository(_context);
UserTitles = new UserTitlesRepository(_context);
UserTokens = new UserTokensRepository(_context);
}
public ICategoriesRepository Categories { get; private set; }
public IOrderDetailsRepository OrderDetails { get; private set; }
public IOrdersRepository Orders { get; private set; }
public IProductImagesRepository ProductImages { get; private set; }
public IProductsRepository Products { get; private set; }
public IUsersRepository Users { get; private set; }
public IUserTitlesRepository UserTitles { get; private set; }
public IUserTokensRepository UserTokens { get; private set; }
public int Complete()
{
return _context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
}
After I have changed my BaseManager class as below:
public abstract class BaseManager
{
private IUnitOfWork _iUow;
public IUnitOfWork IUOW
{
get
{
if (_iUow == null)
{
_iUow = new XaPaUnitOfWork(new XaPaDataContext());
}
return _iUow;
}
}
}
I have achived to receive HttpStatusCode.OK
But, honestly, I'm still unsure about the real reason. I make this correction mostly by heart.

How to access class properties through an Interface instance using Unity.WebApi

Is it possible to expose class public properties in different class through IOC. I am creating an instance of Interface but i am not able to access public properties of class. I am using Unity.WebApi for resolving dependencies.
TransactionService Class
public class TransactionService : ITransactionService
{
private readonly IMRepository _mRepository;
private readonly IFService _fGateway;
public TransactionService(IMbaRepository mbaRepository, IFpnService fpnService)
{
_mRepository = mRepository;
_fGateway = fService;
}
private List<Transaction> SearchTransacionsByUser(FUser objFUser)
{
foreach (var item in something)
{
//can't use _fGateway to set properties because Interface
// don't implement them
_fGateway.OID = objFUser.OID.ToString();
_fGateway.Amount = objFUser.Amount;
_fGateway.Search(criteria);
}
}
}
FService class
public class FService : IFpService
{
public string _OID { get; set; }
public decimal _Amount{ get; set; }
public TransactionResponse Search(string criteria)
{
TransactionOperationInput _input;
_input = new TransactionOperationInput()
{
Criteria = _criteria,
OID = _OID,
Amount = _Amount
};
// search transactions
}
}
If you are in control of the services then refactor the interfaces to expose the desired members
public interface IFService {
TransactionResponse Search(TransactionOperationInput input);
}
Make sure the derived implementation has those members
public class FService : IFpService {
public TransactionResponse Search(TransactionOperationInput input) {
// search transactions
}
}
And that the dependent class uses the correct abstraction
public class TransactionService : ITransactionService {
private readonly IMRepository _mRepository;
private readonly IFService fGateway;
public TransactionService(IMbaRepository mbaRepository, IFService fService) {
_mRepository = mRepository;
fGateway = fService;
}
private List<Transaction> SearchTransacionsByUser(FUser objFUser) {
foreach (var item in something) {
TransactionOperationInput input = new TransactionOperationInput() {
Criteria = _criteria,
OID = objFUser.OID.ToString(),
Amount = objFUser.Amount,
};
fGateway.Search(input);
//...
}
//...
}
}
Finally make sure the register the appropriate abstractions and implementations with the IoC/DI container.

Change business layer class to be loosely coupled

I have below code I am working on. I am working on data access adon.net layer. I have problem with my business layer class called UserBAL. The problem is that I am creating instance of dal and dbmanager inside constructor of UserBAL. How can I change this to be loosely coupled for UserBAL? Hope you get my point.
public interface IEntity
{
int Id { get; set; }
int DoSomething(string one, int two);
}
public class User : IEntity
{
public int Id { get; set; }
public int DoSomething(string one, int two)
{
throw new NotImplementedException();
}
public string Firstname { get; set; }
public string Lastname { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
public class UserBal //busines logic
{
private readonly IRepositoryDal<User> _userRepositoryDal;
public UserBal()
{
_userRepositoryDal = new UserRepositoryDal(new DbManager("sqlserver?"));
}
public IEnumerable<User> SearchByName(string name)
{
return _userRepositoryDal.SearchByName(name);
}
}
interface IRepositoryDal<T> where T : IEntity
{
IEnumerable<T> SearchByName(string username);
T SearchById(string id);
void Update(T entity);
void Remove(T entity);
void Add(T entity);
}
public class UserRepositoryDal: IRepositoryDal<User>
{
private readonly IDbManager _dbManager;
public UserRepositoryDal(IDbManager dbManager)
{
//read from either singleton or configuration file !!
_dbManager = dbManager;
}
public IEnumerable<User> SearchByName(string username)
{
var parameters = new List<IDbDataParameter>
{
_dbManager.CreateParameter("#FirstName", 50, username, DbType.String),
};
var userDataTable = _dbManager.GetDataTable("storedpr2",
CommandType.StoredProcedure, parameters.ToArray());
foreach (DataRow dr in userDataTable.Rows)
{
var user = new User
{
Id = int.Parse(dr["Id"].ToString()),
Firstname = dr["Firstname"].ToString(),
Lastname = dr["LastName"].ToString(),
Email = dr["Email"].ToString()
};
yield return user;
}
}
public User SearchById(string id)
{
var parameters = new List<IDbDataParameter>
{
_dbManager.CreateParameter("#Id", 50, id, DbType.Int32),
};
var userDataTable = _dbManager.GetDataTable("storedpr2",
CommandType.StoredProcedure, parameters.ToArray());
return new User
{
Id = int.Parse(userDataTable.Rows[0]["Id"].ToString()),
Firstname = userDataTable.Rows[0]["Firstname"].ToString(),
Lastname = userDataTable.Rows[0]["LastName"].ToString(),
Email = userDataTable.Rows[0]["Email"].ToString()
};
}
public void Update(User entity)
{
throw new System.NotImplementedException();
}
public void Remove(User entity)
{
throw new System.NotImplementedException();
}
public void Add(User entity)
{
throw new System.NotImplementedException();
}
}
public partial class FrmLogin : Form
{
private readonly UserBal _userBal;
public FrmLogin()
{
InitializeComponent();
_userBal = new UserBal();
}
}
You should use dependency injection, and for required dependencies, you can use constructor injection, e.g:
public class UserBal
{
private readonly IRepositoryDal<User> _userRepositoryDal;
public UserBal(IRepositoryDal<User> userRepositoryDal)
{
_userRepositoryDal = userRepositoryDal
?? throw new ArgumentNullException(nameof(userRepositoryDal));
}
...
}
Dependency injection is the way to go. Here's a simplified example of your situation.
Given your classes could be like this:
public interface IEntity { }
public interface IRepositoryDal<T> where T : IEntity { }
public interface IDbManager { }
public class User : IEntity { }
public class UserBal //busines logic
{
[Injectivity.Attributes.Inject]
private IRepositoryDal<User> _userRepositoryDal;
}
public class UserRepositoryDal: IRepositoryDal<User>
{
[Injectivity.Attributes.Inject]
private IDbManager _dbManager;
}
public class DbManager : IDbManager
{
[Injectivity.Attributes.Construct()]
public DbManager([Injectivity.Attributes.Key("dbKey", typeof(string))] string x)
{
Console.WriteLine($"DbManager created with parameter \"{x}\"");
}
}
...then this code:
var context = Injectivity.Context.CreateRoot();
context.SetConfig<string>("dbKey", "sqlserver?");
context.SetFactory<IDbManager, DbManager>();
context.SetFactory<IRepositoryDal<User>, UserRepositoryDal>();
context.SetFactory<UserBal, UserBal>();
var user = context.Resolve<UserBal>();
...will produce this output:
DbManager created with parameter "sqlserver?"
Now, I've used a DI container that I wrote a number of years back. It's very flexible.
So the call to context.Resolve<UserBal>(); runs down the chain of seeing what needs to be injected to create all of the instances of all of the objects. Ultimately the creation of UserBal requires the DbManager to be created and hence the output.
You would normally not explicitly register each factory. Normally you would put attributes on all of the classes you want to register and then use context.Register(Assembly.LoadFrom("My.DLL")); or create an XML config file and call context.LoadConfig(XDocument.Load("config.xml"));.
You can even do things like this:
context.SetDecorator<IRepositoryDal<User>, UserRepositoryDalDecorator>();
This will cause all calls to context.Resolve<IRepositoryDal<User>>() or [Inject] attributes to automatically wrap the real instances in this decorator. Ideal to intercepting method calls for debugging purposes.

How to inject a parameter constructor into Repository constructor using Ninject?

I am trying to create DBContect object by passing connection string at run time.
Following is the structure of my NiNject Repository implementation.
public class HomeController : ApiController
{
MyService _service{ get; set; }
public HomeController(MyService service)
{
_service= service;
}
}
public class MyService
{
IRepository _repo { get; set; }
public MyService(IRepository repo)
{
_repo = repo;
}
}
Repository implementation is as follows :
public interface IRepository
{
TenantDbContext _db { get; set; }
void Add<T>(T entity) where T : class;
void Delete<T>(int id) where T : class;
T Find<T>(int id) where T : class;
IQueryable<T> Query<T>() where T : class;
void SaveChanges();
MasterDbContext _db_master { get; set; }
void Add_Master<T>(T entity) where T : class;
void Delete_Master<T>(int id) where T : class;
T Find_Master<T>(int id) where T : class;
IQueryable<T> Query_Master<T>() where T : class;
void SaveChanges_Master();
}
public class Repository : IRepository
{
public TenantDbContext _db { get; set; }
public MasterDbContext _db_master { get; set; }
public Repository(TenantDbContext db)
{
_db = db;
}
public Repository(MasterDbContext db_master)
{
_db_master = db_master;
}
public IQueryable<T> Query<T>() where T : class
{
return _db.Set<T>().AsQueryable();
}
public IQueryable<T> Query_Master<T>() where T : class
{
return _db_master.Set<T>().AsQueryable();
}
//.....Rest of the implemetation
}
Here goes my TenantDBContext class which takes an argument as a database string. No default constructor
public class TenantDbContext : DbContext
{
public TenantDbContext(string connString)
: base(connString)
{
//Configuration.AutoDetectChangesEnabled = true;
//Configuration.LazyLoadingEnabled = false;
//Configuration.ProxyCreationEnabled = false; //change tracking
}
public static TenantDbContext Create(string DbString)
{
// Some logic to get the tenant database string.
// Presently i am just passing it hard coded as follows.
return new TenantDbContext(DbString);
}
}
public class MasterDbContext : IdentityDbContext<ApplicationUser>
{
public MasterDbContext() : base("MasterDBConnection", throwIfV1Schema: false)
{
// dbmigration.AutomaticMigrationsEnabled = true;
Configuration.ProxyCreationEnabled = false;
Configuration.LazyLoadingEnabled = false;
}
public static MasterDbContext Create()
{
return new MasterDbContext();
}
//public DbSet<ApplicationUser> ApplicationUsers { get; set; }
public DbSet<Tenant> Tenants { get; set; }
public DbSet<TenantUserMap> TenantUserMaps { get; set; } }
Finally, RegisterServices which i have in my NinjectWebCommons.cs looks as follows :
Each Tenant have its different database. We are fetching out the Tenant name from the access token on every request and caching that requested Tenant object so we can pass the correct Tenant Database string in order to do the operations on the requested Tenant Database.
Below snippet, We are fetching the Tenant object from the current request cache which will provide us the Tenant Database string of the requested client.
public Tenant Tenant
{
get
{
object multiTenant;
if (!HttpContext.Current.GetOwinContext().Environment.TryGetValue("MultiTenant", out multiTenant))
{
throw new ApplicationException("Could Not Find Tenant");
}
return (Tenant)multiTenant;
}
}
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IRepository>().To<Repository>();
kernel.Bind<TenantDbContext>().ToMethod(_ =>
TenantDbContext.Create(Tenant.DBString));
kernel.Bind<MasterDbContext>().ToMethod(__ => MasterDbContext.Create());
}
Problem : When i add second binding in my NinjectWebCommons.cs "kernel.Bind()" , i start getting exception saying that "No default constructor found". It is simply not taking two bindings with the kernal. Request you to please have a look at the code above and point me out where i am going wrong.
I will appreciate your help. Thanks in Advance.
You may add a binding for the database context and point Ninject to use your factory method:
kernel.Bind<TenantDbContext>().ToMethod(_ => TenantDbContext.Create());

Categories