how to inject depencies to constructor controller - api

I'm trying to configure an API which a controller use depency injection to inject an object to this controller
public class BaseAPIController
{
private readonly Repository _repository;
public BaseAPIController(Repository repository)
{
_repository = repository;
}
// some common functions and properties are declared here
}
public class AccountController : BaseAPIController
{
public AccountController(Repository repository) : base(repository)
{ }
}
but it throws an exception that tells "Some services are not able to be constructed..."
I tried a solution that use ILogger<Repository> instead of using Repository instance then this runs properly
public class AccountController : BaseAPIController
{
public AccountController(ILogger<Repository> repository) : base(repository)
{ }
}
the registion service in startup.cs code
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddScoped<IRepository, Repository>();
services.AddSingleton<WeatherForecastController, WeatherForecastController>();
}
and the declaration of Repository class
public interface IRepository
{
void DoSomething1();
void DoSomething2();
void DoSomething3();
}
public class Repository : IRepository
{
public readonly string _connectionString;
public Repository(string connectionString)
{
_connectionString = connectionString;
}
public void DoSomething1() {}
public void DoSomething2() {}
public void DoSomething3() {}
}
How can I archive the configuration above without using ILogger instance
Thanks

This is the registration you made:
services.AddScoped<IRepository, Repository>();
But this is AccountController's constructor:
AccountController(Repository repository)
Notice how AccountController is depending on the concrete type Repository; not on the IRepository interface. Because of this registration, Repository can only be resolved through its IRepository interface, but not directly (that's by MS.DI's design).
The solution, therefore, is to change AccountController's constructor to the following:
AccountController(IRepository repository)

The issue is that DI cannot create an instance of Repository because there is no parameterless constructor. Take a look at the docs for injecting settings rather than requiring a string in the constructor. Add your connection string to your appsettings.json file:
{
"AppSettings": {
"ConnectionString": "<connection_string>"
}
}
In ConfigureServices register your settings class:
public class AppSettings
{
public string ConnectionString;
}
public void ConfigureServices(IServiceCollection services)
{
services.Configure<AppSettings>(Configuration.GetSection(AppSettings));
...
}
Then your Repository class constructor would look like this:
public Repository(IOptions<PositionOptions> options)
{
_connectionString = options.Value.ConnectionString;
}
You also need to inject the interface IRepository, not the concrete class into your controller.
public class BaseAPIController
{
private readonly IRepository _repository;
public BaseAPIController(IRepository repository)
{
_repository = repository;
}
// some common functions and properties are declared here
}

Related

ASP.NET Core - Create a singleton class to supply connection string across the application

I'm creating a ASP.NET Core Web API using ADO.NET (without Entity Framework). I need a singleton class to supply connection string to all the controllers. I have done the following.
Defined a class DBUtils to have just one public property DBConnectionString.
Try to register the class as a singleton in startup.cs.
Use the class through DI in each controller to access the connection string.
public class DBUtils
{
public string DBConnectionString { get; set; }
public DBUtils(string connectionString)
{
this.DBConnectionString = connectionString;
}
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<DBUtils>();
services.AddControllers();
}
}
public class CommonController : ControllerBase
{
private string conStr;
public CommonController(DBUtils utils)
{
conStr = utils.DBConnectionString;
}
public IActionResult GetData() {
SqlConnection connection = new SqlConnection(conStr);
//Get dat from the database
return null;
}
}
Now the problem is I'm not able to pass the connection string to the DBUtils constructor. I read from other posts that we should not use parameters to Singleton classes. But my class will only have one parameter and it will never change during execution. It gets the connection string from config file.
please help how to I pass connection string to my controllers.
I don't want to use IConfiguration as DI in the controller class directly.
UPDATE: I realised that Singleton is not the approach for my requirement and as #Ceemah Four suggested we should use Options Pattern.
Thanks
This scenario has already been catered for in dotnet core.
You do not need to create the DBUtils class. Neither do you need to set up the Singleton DI etc.
Assuming this is your appsettings.json
"ConnectionStrings": {
"SqlDatabase": "connection string here"
}
There are two potential approaches:
Inject IConfiguration in Controller constructor - you can simply access the connection string value from the injected Configuration.
public class CommonController : ControllerBase
{
private readonly IConfiguration _config;
private string conStr;
public CommonController(IConfiguration config)
{
_config = config;
}
public IActionResult GetData()
{
SqlConnection connection = new SqlConnection(_config.GetConnectionString("SqlDatabase"));
//Get data from the database
return null;
}
}
Create a Settings class, bind the settings class in Startup and inject the Settings class in the controller constructor. This uses the IOPtions pattern * and is a cleaner and recommended approach*
public class ConnectionSettings
{
public string SqlDatabase { get; set; }
}
In your startup.cs:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<ConnectionSettings>(Configuration.GetSection("ConnectionStrings"));
services.AddControllers();
}
}
Then in your controller:
public class CommonController : ControllerBase
{
private readonly IOptions<ConnectionSettings> _connectionSettings;
public CommonController(IOptions<ConnectionSettings> connectionSettings)
{
_connectionSettings = connectionSettings;
}
public IActionResult GetData()
{
SqlConnection connection = new SqlConnection(_connectionSettings.Value.SqlDatabase));
//Get data from the database
return null;
}
}

.NET Core how to DI DbContext to AuthrozationFilter

like as title
I setting db context on Startup.cs
services.AddDbContext<MyContext>(options => options.UseSqlServer(connectionStr));
and I want using it on AuthrozationFilter constructor like this
public class AuthrozationFilter : Attribute, IAuthorizationFilter
{
private readonly MyContext _db;
public AuthrozationFilter(MyContext db)
{
this._db = db;
}
}
but it doesn't work, how to do that ?
You can use service location to resolve components from the built-in IoC container by using RequestServices.GetService:
public class AuthrozationFilter : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var dbcontext= context.HttpContext.RequestServices.GetRequiredService<MyContext>();
}
}
Or you can use ServiceFilter/TypeFilter :
public class AuthrozationFilter : IAuthorizationFilter
{
private readonly MyContext _db;
public AuthrozationFilter(MyContext db)
{
this._db = db;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
}
}
And add [TypeFilter(typeof(AuthrozationFilter))] on controllers/actions . Please refer to below documents for filters in asp.net core :
https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-3.1
https://www.devtrends.co.uk/blog/dependency-injection-in-action-filters-in-asp.net-core
Found another way to do it. Under the covers this is wrapping ServiceFilter
Use the AddService api on Action<MvcOptions>
serviceCollection.AddControllers(c => c.Filters.AddService<AuthrozationFilter>())
Need to register your service with dependency injection
serviceCollection.AddScoped<AuthrozationFilter>();
Then inject via the constructor
public class AuthrozationFilter : IAuthorizationFilter
{
private readonly MyContext _db;
public AuthrozationFilter(MyContext db)
{
this._db = db;
}
}
Adds the filter to all controllers. If you need more targeted, probably use ServiceFilterAttribute directly.

What is the best way to wrap dbContext for DI?

I am thinking something like the following may work ok for injecting dbcontext via constructor to my service layer.... Does anyone out there have a better way?
It seems to work however _context.EntityName etc don't show up in intellisense unless I cast the object to the actual class that inherits from dbcontext.
public interface IContextFactory:IDisposable
{
DbContext Create();
}
public class ContextFactory<TContext> : IContextFactory where TContext : DbContext, new()
{
private DbContext _context;
public DbContext Create()
{
_context = new TContext();
_context.Configuration.LazyLoadingEnabled = true;
return _context;
}
public void Dispose()
{
_context.Dispose();
}
}
As Steven mentioned in his comment, you can just inject the DbContext directly from your Composition Root. Here is an example of how this could work with SimpleInjector.
container.Register<MyDbContext>(
() => new MyDbContext("name=MyDbContext"),
new WebRequestLifestyle(true));
Where MyDbContext is a subclass of DbContext:
public class MyDbContext: DbContext
{
public MyDbContext(string connectionString)
: base(connectionString)
{
this.Configuration.LazyLoadingEnabled = true;
}
/* DbSets<SomeEntity> etc */
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//etc
}
}

Unit Of Work & Generic Repository with Entity Framework 5

I'm using ASP.NET MVC 4 with Entity Framework 5. I have model classes and Entity Maps to map existing tables to those model classes. All this is setup fine and works great.
Now I want to mock this. I created Unit Of Work that takes the DataContext and uses a Generic Repository. Upon that I built services to be able to get data from many repositories at once and only needing to have one instance of the DataContext. This also works great.
Now to the problem: I want to test the services, with mock data. When I create the Unit Of Work instance, I want to be able to insert a DataContext that is mocked instead of the real DataContext.
I tried to create a IContext interface and let the real and mocked DataContext implement that but ran into problems with DbSet. I tried to use IDbSet and creating a FakeDbSet but without success. I also read on the internet that mocking the context with IDbSet and using a FakeDbSet is a bad approach.
Do you have any idea what would be the best way to achieve this? What I have now is the behavior I would like to keep, but would really like to be able to mock the data from the Model classes in the DataContext.
I'm aware of that Entity Framework already comes with Unit Of Work behavior and that you don't need to add extra behavior on top of that. But I wanted to wrap that inside of another class that keeps track of all the repositories (called UnitOfWork class).
Edit: I wrote two articles explaining my solution with both LINQ and Entity Framework.
http://gaui.is/how-to-mock-the-datacontext-linq/
http://gaui.is/how-to-mock-the-datacontext-entity-framework/
Here's my code:
IRepository.cs
public interface IRepository<T> where T : class
{
void Add(T entity);
void Delete(T entity);
void Update(T entity);
T GetById(long Id);
IEnumerable<T> All();
IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
}
IUnitOfWork.cs
public interface IUnitOfWork : IDisposable
{
IRepository<TEntity> GetRepository<TEntity>() where TEntity : class;
void Save();
}
Repository.cs
public class Repository<T> : IRepository<T> where T : class
{
private readonly IDbContext _context;
private readonly IDbSet<T> _dbset;
public Repository(IDbContext context)
{
_context = context;
_dbset = context.Set<T>();
}
public virtual void Add(T entity)
{
_dbset.Add(entity);
}
public virtual void Delete(T entity)
{
var entry = _context.Entry(entity);
entry.State = System.Data.EntityState.Deleted;
}
public virtual void Update(T entity)
{
var entry = _context.Entry(entity);
_dbset.Attach(entity);
entry.State = System.Data.EntityState.Modified;
}
public virtual T GetById(long id)
{
return _dbset.Find(id);
}
public virtual IEnumerable<T> All()
{
return _dbset;
}
public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
{
return _dbset.Where(predicate);
}
}
UnitOfWork.cs
public class UnitOfWork<TContext> : IUnitOfWork where TContext : IDbContext, new()
{
private readonly IDbContext _ctx;
private Dictionary<Type, object> _repositories;
private bool _disposed;
public UnitOfWork()
{
_ctx = new TContext();
_repositories = new Dictionary<Type, object>();
_disposed = false;
}
public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
{
if (_repositories.Keys.Contains(typeof(TEntity)))
return _repositories[typeof(TEntity)] as IRepository<TEntity>;
var repository = new Repository<TEntity>(_ctx);
_repositories.Add(typeof(TEntity), repository);
return repository;
}
public void Save()
{
_ctx.SaveChanges();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this._disposed)
{
if (disposing)
{
_ctx.Dispose();
}
this._disposed = true;
}
}
}
ExampleService.cs
public class ExampleService
{
private IRepository<Example> m_repo;
public ExampleService(IUnitOfWork uow)
{
m_repo = uow.GetRepository<Example>();
}
public void Add(Example Example)
{
m_repo.Add(Example);
}
public IEnumerable<Example> getAll()
{
return m_repo.All();
}
}
ExampleController.cs
public IEnumerable<Example> GetAll()
{
// Create Unit Of Work object
IUnitOfWork uow = new UnitOfWork<AppDataContext>();
// Create Service with Unit Of Work attached to the DataContext
ExampleService service = new ExampleService(uow);
return service.getAll();
}
Your ExampleService class is expecting IUnitOfWork, that means you just need another IUnitOfWork that is a Mock and its GetRepository() method will return an IRepository Mock.
For example (not really a Mock but In-Memory stub):
public InMemoryRepository<T> : IRepository<T> where T : class
{
........
}
public InMemoryUnitOfWork : IUnitOfWork
{
public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
{
return new InMemoryRepository<TEntity>();
}
}
Then:
public IEnumerable<Example> GetAll()
{
// Create Unit Of Work object
IUnitOfWork uow = new InMemoryUnitOfWork();
// Create Service with Unit Of Work
ExampleService service = new ExampleService(uow);
return service.getAll();
}
You can follow the following link it is very helpful.
Generic Repository Pattern in MVC3 Application with Entity Framework
Entity Framework and Data Patterns

Ninject Several constructors have the same priority

I can't get rid of the exception which comes from Ninject "Several constructors have the same priority"
I have repository
public interface IRepository<TEntity> where TEntity : class
{
List<TEntity> FetchAll();
IQueryable<TEntity> Query { get; }
void Add(TEntity entity);
void Delete(TEntity entity);
void Save();
}
public class Repository<T> : IRepository<T> where T : class
{
private readonly DataContext _db;
public Repository(DataContext db)
{
_db = db;
}
#region IRepository<T> Members
public IQueryable<T> Query
{
get { return _db.GetTable<T>(); }
}
public List<T> FetchAll()
{
return Query.ToList();
}
public void Add(T entity)
{
_db.GetTable<T>().InsertOnSubmit(entity);
}
public void Delete(T entity)
{
_db.GetTable<T>().DeleteOnSubmit(entity);
}
public void Save()
{
_db.SubmitChanges();
}
#endregion
}
Controller where I am trying to bind repository
public class AdminController : Controller
{
private readonly IRepository<Store> _storeRepository;
public AdminController(IRepository<Store> storeRepository)
{
_storeRepository = storeRepository;
}
}
Ninject boot strapper
private static void RegisterServices(IKernel kernel)
{
var connectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
kernel.Bind(typeof (DataContext)).ToMethod(context => new DataContext(connectionString));
kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>));
}
After I run app I get error
Error activating DataContext using implicit self-binding of DataContext
Several constructors have the same priority. Please specify the constructor using ToConstructor syntax or add an Inject attribute.
Constructors:
DataContext(string fileOrServerOrConnectionMappingSource mapping)
DataContext(IDbConnection connectionMappingSource mapping)
It seems that Ninject tries to bind to DataContext class constructor
namespace System.Data.Linq: IDisposable
{
public class DataContext : IDisposable
{
public DataContext(IDbConnection connection);
public DataContext(string fileOrServerOrConnection);
//skip code
}
but I want to bind to my repository constructor
public class Repository<T> : IRepository<T> where T : class
{
private readonly DataContext _db;
public Repository(DataContext db)
{
_db = db;
}
//skip code
}
Also if I remove line below form boot strapper I still get the same exception. It seems Ninject automatically tries to bind dependencies when I am trying to bind Repository.
kernel.Bind(typeof (DataContext)).ToMethod(context => new DataContext(connectionString));