Dependency injection at runtime using Ninject - c#

How do I inject a specific dependency using Ninject when which class to inject is only determined at runtime? I have an interface and implmentations as follows:
public interface ICompanyDAL
{
Company LoadProfile(int companyID);
}
public class TechCompanySqlDAL : ICompanyDAL
{
Company LoadProfile(int companyID)
{
//Call Stored procs related to TechCompany
//Populate Model class TechCompany which is derived from abstract class Company
}
}
public class BankingCompanySqlDAL : ICompanyDAL
{
Company LoadProfile(int companyID)
{
//Call Stored procs related to BankingCompany
//Populate Model class BankingCompany which is derived from abstract class Company
}
}
I have a service class that needs to call one of the two concrete classes as follows.
public class CompanyService
{
private readonly ICompanyDAL companyDAL;
public CompanyHousingService(ICompanyDAL compDAL)
{
this.companyDAL = compDAL;
}
public Company LoadProfile(int companyID, CompanyType type)
{
if(type == CompanyType.Tech)
//Need to call TechCompanyDAL
else if (type == CompanyType.Banking)
//Need to call BankingCompanyDAL
}
}
I don't want Service class to be dependent on any of the concrete classes, because those might change. Also we might add more company typese. So how do I inject ICompanyDAL into the service based on reflection.
I am also open to suggestions on changing the above pattern if anyone explains a better alternative.

There are many approaches to solve that you can use ganerics for example, but one of them is this:
you can change the ctor dependency to IEnumerable<ICompanyDAL>.
so maybe this will works fine to you, see the code below:
public interface ICompanyDAL
{
CompanyType CompanyType {get;}
Company LoadProfile(int companyID);
}
public class TechCompanySqlDAL : ICompanyDAL
{
public CompanyType CompanyType => CompanyType.Tech;
Company LoadProfile(int companyID)
{
//Call Stored procs related to TechCompany
//Populate Model class TechCompany which is derived from abstract class Company
}
}
public class BankingCompanySqlDAL : ICompanyDAL
{
public CompanyType CompanyType => CompanyType.Banking;
Company LoadProfile(int companyID)
{
//Call Stored procs related to BankingCompany
//Populate Model class BankingCompany which is derived from abstract class Company
}
}
Now the Service:
public class CompanyService
{
private readonly IEnumerable<ICompanyDAL>compDALs;
public CompanyHousingService(IEnumerable<ICompanyDAL> compDALs)
{
this.companyDALs = compDALs;
}
public Company LoadProfile(int companyID, CompanyType type)
=> companyDALs.FirstOrDefault(s => s.CompanyType==type)?.LoadProfile(companyID);
}

You can make the ICompanyDAL generic and inject two dependencies into CompanyService like this:
public interface ICompanyDAL<T> where T:Company
{
T LoadProfile(int companyID);
}
public class TechCompanySqlDAL : ICompanyDAL<TechCompany>
{
public TechCompany LoadProfile(int companyID)
{
//Call Stored procs related to TechCompany
//Populate Model class TechCompany which is derived from abstract class Company
}
}
public class BankingCompanySqlDAL : ICompanyDAL<BankingCompany>
{
public BankingCompany LoadProfile(int companyID)
{
//Call Stored procs related to BankingCompany
//Populate Model class BankingCompany which is derived from abstract class Company
}
}
public class CompanyService
{
private readonly ICompanyDAL<BankingCompany> bankingCompanyDAL;
private readonly ICompanyDAL<TechCompany> techCompanyDAL;
public CompanyService(ICompanyDAL<BankingCompany> banking_company_dal, ICompanyDAL<TechCompany> tech_company_dal)
{
bankingCompanyDAL = banking_company_dal;
techCompanyDAL = tech_company_dal;
}
public Company LoadProfile(int companyID, CompanyType type)
{
if (type == CompanyType.Tech)
return techCompanyDAL.LoadProfile(companyID);
else if (type == CompanyType.Banking)
return bankingCompanyDAL.LoadProfile(companyID);
//handle case of invalid type
}
}
And here is how you would register the dependencies and resolve your CompanyService object:
StandardKernel kernel = new StandardKernel();
kernel.Bind<ICompanyDAL<TechCompany>>().To<TechCompanySqlDAL>();
kernel.Bind<ICompanyDAL<BankingCompany>>().To<BankingCompanySqlDAL>();
var service = kernel.Get<CompanyService>();

Related

Is it possible to pass a DbContext from one project into another project?

The scenario:
I have a couple websites that I'm rebuilding with Blazor, all do e-commerce. What I want to do is extract the accounting logic (i.e. Orders, OrderItems, Accounts, Transactions, etc) and data operations into an
"Accounting" DLL so I don't have to repeat the code.
I've got the above Entities defined in the DLL, then in the WebApp.Server's DbContext I have the appropriate DbSets.
In the "Accounting" DLL, I have an interface:
public interface IDbAccountringService
{
DbSet<Account> Accounts { get; set; }
//etc
}
which the DbContext in WebApp.Server implements:
public class Db : ApiAuthorizationDbContext<User>, IDbAccountringService
{
public Db(
DbContextOptions options,
IOptions<OperationalStoreOptions> operationalStoreOptions) : base(options, operationalStoreOptions)
{
}
public DbSet<Account> Accounts { get; set; }
}
Then in the "Accounting" DLL, I have the following generic class:
public class DbAccountingService<T> where T : DbContext, IDbAccountringService
{
DbContext dbContext { get; set; }
public DbAccountingService(DbContext T)
{
dbContext = T;
}
public Account[] GetAccounts()
{
//The compiler doesn't see Accounts
return dbContext.Accounts.ToArray();
//It also doesn't see Accounts on itself
return this.Accounts.ToArray();
// However, it does see all the DbContext methods
dbContext.SaveChanges();
}
}
which I instantiate and use in my controller:
[Route("accounting/accounts")]
[ApiController]
public class JournalController : BaseApiController
{
DbAccountingService<Db> _dbAccountingService;
public JournalController(Db db, MtGlobals mtGlobals) : base(mtGlobals)
{
_dbAccountingService = new DbAccountingService<Db>(db);
}
[HttpGet("get-accounts")]
public Account[] GetAccounts()
{
return _dbAccountingService.GetAccounts();
}
}
As the comments in DbAccountingService<T> indicate, the compiler recognizes that dbContext is in fact a DbContext, but it doesn't recognize that it also implements IDbAccountringService.
I'm a little fuzzy on generics, though I usually get them working, however, here, no luck.
Is what I'm trying to do possible? I want to extract all the data operations into the "Accounting" DLL so that I don't have to write duplicate code for each website.
Your dbContext field is of type DbContext:
DbContext dbContext { get; set; }
public DbAccountingService(DbContext T)
{
dbContext = T;
}
Be aware, that you constructor parameter is of type DbContext too with parameter name T. So this T has nothing to do with the generic type parameter, it's just a parameter name.
You want the dbContext property to be the generic type:
T dbContext { get; set; }
public DbAccountingService(T context)
{
dbContext = context;
}
The relevant par is, that your field has type T (because your where constraints this to implement interface IAccountingService.

How to convert data of IList<Object> to IEnumerable<OtherObject> with AutoMapper?

Class with IList<Object> member:
public class RegisterGroupEmployeeRequest : GroupEmployeeBase
{
public IList<EmployeeBase> Employee { get; set; }
}
Class with IEnumerable<OtherObject> member:
public class RegisterGroupEmployeeCommand
{
public RegisterGroupEmployeeCommand(Guid groupId, IList<EmployeeCommand> employee)
{
Employee = employee;
}
public IEnumerable<EmployeeCommand> Employee { get; protected set; }
}
Mapper:
CreateMap<RegisterGroupEmployeeRequest, RegisterGroupEmployeeCommand>()
.ConstructUsing(src => new RegisterGroupEmployeeCommand(src.GroupId, src.Employee));
How can I convert data of IList<Object> to IEnumerable<OtherObject> with AutoMapper?
Or is there any another solution for converting this kind issue?
tl;dr
Remove the .ConstructUsing() and leave the entry like below:
CreateMap<RegisterGroupEmployeeRequest, RegisterGroupEmployeeCommand>();
In this line:
.ConstructUsing(src => new RegisterGroupEmployeeCommand(src.GroupId, src.Employee));
Your Employee is of IList<EmployeeCommand> type but you are trying to pass IList<EmployeeBase> instead.
Since you already have the entry like:
CreateMap<EmployeeBase, EmployeeCommand>();
AutoMapper will handle the conversion from IList<EmployeeBase> to IList<EmployeeCommand> as well.
Passing Group goupId seems to be unnecessary as you don't use it in the constructor body.
public RegisterGroupEmployeeCommand(Guid groupId, IList<EmployeeCommand> employee)
{
Employee = employee;
}
Looking at point 2. and 3. you don't need the .ConstructUsing(...) line.

Have a base entity class with CRUD implementation and a primary key ID that can be changed by the classes implementing it

In order to not rewrite basic CRUD for each entity I want to implement a base entity class with the base CRUD operations that can be implemented by any other entity.
The problem is I'm using Dapper for mapping with Dapper.Contrib and my database tables primary keys are never named Id - I can't use the Dapper mapper then.
I can't figure out a way to have a base class for a simple CRUD for each entity.
There is a very nice implementation without contrib of the generic repository pattern here: https://itnext.io/generic-repository-pattern-using-dapper-bd48d9cd7ead
Effectively you create the insert like this:
public async Task InsertAsync(T t)
{
var insertQuery = GenerateInsertQuery();
using (var connection = CreateConnection())
{
await connection.ExecuteAsync(insertQuery, t);
}
}
private string GenerateInsertQuery()
{
var insertQuery = new StringBuilder($"INSERT INTO {_tableName} ");
insertQuery.Append("(");
var properties = GenerateListOfProperties(GetProperties);
properties.ForEach(prop => { insertQuery.Append($"[{prop}],"); });
insertQuery
.Remove(insertQuery.Length - 1, 1)
.Append(") VALUES (");
properties.ForEach(prop => { insertQuery.Append($"#{prop},"); });
insertQuery
.Remove(insertQuery.Length - 1, 1)
.Append(")");
return insertQuery.ToString();
}
Even though #Athanasios Kataras answer works I still went with using the Dapper.contrib extension because it's more clear in my opinion.
I went the route of using Dapper.contrib and creating a Base Repository class which then was used by every other repository.
Primary Keys (IDs) were handled by using data annotations that Dapper provides on the entities ([Key], [ExplicitKey]).
Example of some repository class implementing the Base Repository:
public class ACRepository : BaseRepository<ACEntity>, IACRepository
{
private readonly IDbConnection _dbConnection;
public ACRepository(IDbConnection _dbconn) : base(_dbconn)
{
_dbConnection = _dbconn;
}
// Some other methods that require more complicated queries
}
Base Repository class:
using Dapper.Contrib.Extensions;
public class BaseRepository<T> : IBaseRepository<T> where T : class
{
private readonly IDbConnection _dbConnection;
public BaseRepository(IDbConnection _dbconn)
{
_dbConnection = _dbconn;
}
public async Task Add(T entity)
{
var result = await _dbConnection.InsertAsync(entity);
}
public async Task<bool> Delete(T entity)
{
return await _dbConnection.DeleteAsync(entity);
}
public async Task<bool> Update(T entity)
{
return await _dbConnection.UpdateAsync(entity);
}
public async Task<T> GetById(object id)
{
return await _dbConnection.GetAsync<T>(id);
}
public async Task<IEnumerable<T>> GetAll()
{
return await _dbConnection.GetAllAsync<T>();
}
}
An Entity:
using Dapper.Contrib.Extensions;
[Table("table_name")]
public class SquawkRegisterPMEEntity
{
[ExplicitKey]
public string SomeKey { get; set; }
[Key]
public int SomeOtherKey{ get; set; }
public string SomeProperty { get; set; }
public string SomeProperty1 { get; set; }
}
[Key] is used if the value is generated by the database.
[ExplicitKey] is used when the Id is specified manually.

Group methods in Abstract Class

I'm working on a database factory pattern for an application which should support Sql Server and Oracle. I've an abstract classes with all the Sql Queries for the application. I've implemented the abstract class in two classes: SqlServerClass and OracleClass. Based on the connection string defined in the configuration file, the application creates an instance of the corresponding class and get the Sql queries for the database.
public abstract class ProviderFactory
{
public abstract string GetCustomersSql();
public abstract string GetCustomersByIdSql();
public abstract string GetUsersSql();
public abstract string GetUsersByIdSql();
}
public class OracleClass : ProviderFactory
{
public override string GetCustomersSql()
{
// return sql query for Oracle
}
// other methods
}
public class SqlServerClass : ProviderFactory
{
public override string GetCustomersSql()
{
// return sql query for Sql Server
}
// other methods
}
Now my question is, Is there a way to group these sql queries in the abstract class so that one can easily identify the sql queries used for particular functionality. For example, Can I group all Customers related queries and Users related queries so that when I refer them, it would be like....
ProviderFactory instance;
// create an instance
instance.Customers.GetCustomersSql();
Is what I'm doing here a valid approach? Please suggest. Thank you.
I would strongly recommend using an ORM such as NHibernate. It supports both SQL Server and Oracle and abstracts away the differences between the two.
By that I mean you only have to write the query once in a format NHibernate understands and it will translate that to versions that SQL Server and Oracle understand.
If you want to continue down your current path what you can do is create what I'd call a query directory:
public interface IQueryDirectory
{
ICustomerQueries Customer { get; }
IUserQueries User { get; }
}
public interface ICustomerQueries
{
string Customers { get; }
string CustomersById { get; }
}
public interface IUserQueries
{
string Users { get; }
string UsersById { get; }
}
Example implementation:
public abstract class QueryDirectory : IQueryDirectory
{
private ICustomerQueries customer;
private IUserQueries user;
public ICustomerQueries Customer
{
get { return customer; }
}
public IUserQueries User
{
get { return user; }
}
protected QueryDirectory(ICustomerQueries customer, IUserQueries user)
{
this.customer = customer;
this.user = user;
}
}
public class SqlServerQueryDirectory : QueryDirectory
{
public SqlServerQueryDirectory(SqlServerCustomerQueries customer,
SqlServerUserQueries user) : base(customer, user) {}
}
public class SqlServerCustomerQueries : ICustomerQueries
{
public string Customers
{
get "some sql";
}
public string CustomersById
{
get "some sql";
}
}
Then you can implement the directories seperately for each database. But honestly, I really, really, really recommend using an ORM instead.

Linq 2 SQL - A Better way of doing this

I have a repository base class that gets called from my controllers in my mvc application
Each controller gets it own repository
like this
public class ServiceRepository : Bluegrass.Mvc.RepositoryBase<Models.Service>
{
public ServiceRepository()
{
this._db = new iSppms.Models.iSppmsDataContext();
}
}
And gets used like
internal DataAccess.ServiceRepository repository =
new iSppms.DataAccess.ServiceRepository();
public ActionResult Index()
{
var viewData = new ViewData.ServiceIndexViewData(
repository.GetItems<Models.Service>());
return View(viewData);
}
Where I am wanting to do is not have to pass the model through as the RepositoryBase is already of type Models.Service
I am looking for a better way to structure this.
public class RepositoryBase<T> where T : class
{
public DataContext _db;
public List<T> GetItems<T>() where T : class, Interfaces.IModel
{
var table = _db.GetTable<T>();
var data = table.Where(t => !t.Deleted);
return data.ToList();
}
Can you add the IModel bit to RepositoryBase<T>, and make GetItems<T> non-generic? Note: it is already a bad idea to re-use the generic token T (which is different in GetItems):
public class RepositoryBase<T> where T : class, Interfaces.IModel
{
public DataContext _db;
public List<T> GetItems()
{
var table = _db.GetTable<T>();
var data = table.Where(t => !t.Deleted);
return data.ToList();
}
}
Perhaps this Repository Base Class article could help?

Categories

Resources