Isuue with my dependency having dependencies (ASP.NET Core) - c#

So I have a repository class that looks as following:
public class StationsRepository : IStationsRepository
{
private readonly AftermarketDbContext _db;
public StationsRepository(DbContext db)
{
_db = db;
}
and in my startup.cs class i have added it to services as following.
services.AddTransient<IStationsRepository, StationsRepository>();
And in my controller I have injected it as following:
public RpcApiController(AftermarketDbContext db,IStationsRepository stationsRepository)
{
_db = db;
_stationsRepository = stationsRepository;
}
But my issue is how do I use it when I need it in the controller because it needs a database to be sent to the constructor so where so I do that? What would a example of using the repositories "GetStation" method look like for example?

Related

.NET MVC + Unity: some basic help needed

MVC application using Identity and EF.
I want to implement dependency injection using Unity.
I have installed Unity in the project (both Unity and Unity.mvc5), but now I am lost at how to implement it...
As of now, (before changing anything) I instantiate dbcontext in every controller, then in controller constructor I create service instances with new xxxx(db).
My controllers are like this:
public class SomeController : Controller {
private ApplicationDbContext db = new ApplicationDbContext("DefaultConnection");
private XxService xxService;
public SomeController() {
this.xxService = new XxService(db);
}
public ActionResult Index() {
string name = xxService.Foo(5);
return View();
}
}
then I have my Services:
public class XxService {
private ApplicationDbContext db;
private YyService yyService;
public XxService(ApplicationDbContext db) {
this.db = db;
this.yyService = new YyService(db);
}
public string Foo(int id) {
Customer customer = yyService.Bar(id);
return customer.Name;
}
}
public class YyService {
private ApplicationDbContext db;
public YyService(ApplicationDbContext db) {
this.db = db;
}
public Customer Bar(int id) {
return db.Customers.Find(id);
}
}
and the unity config:
public static class UnityConfig {
public static void RegisterComponents() {
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
//container.RegisterType<XxService>(new Unity.Injection.InjectionConstructor());
}
}
I dont really understand what and how should I register in Unity config, and/or what interfaces should I create...
Should I register the Services? the dbcontext? both? and... how? some code would be great, this is driving me nuts...
Yes, you have to put every registration of the interface\concrete implementation pair inside of RegisterComponents(). I assume you defined interface for you DbContext class. So you have done pretty much everything except registering services:), like this:
var container = new UnityContainer();
container.RegisterType<IService1, Service1>(new PerRequestLifetimeManager());
container.RegisterType<IService2, Service2>(new SingletonLifetimeManager());
container.RegisterType<IMyDbContext, MyDbContext>(new PerRequestLifetimeManager(),
new InjectionConstructor("name=MyDbConnection");
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
Unity Container / Microsoft Dependency Injection
https://github.com/unitycontainer/microsoft-dependency-injection

Declaring a controller-level instance of the database context

In a controller, is there any difference between declaring a database context instance like this:
public class MyController : Controller
{
private readonly MyDatabaseEntities _context = new MyDatabaseEntities();
public ActionResult Index()
{
...
}
}
Versus this:
public class MyController : Controller
{
private readonly MyDatabaseEntities _context;
public MyController()
{
_context = new MyDatabaseEntities();
}
public ActionResult Index()
{
...
}
}
I'm just beginning to realise that the way I've been handling database context in my ASP.NET apps may not have been correct (or at least ideal) for a while and I'm reading up on it and thinking of how I'm going to start using Dependency Injection, but for starters I was just wondering if I'm even instantiating database contexts in my controllers correctly.
Incidentally, I'm still working in .NET Framework 4.7.2. Hopefully we'll start working in .NET 5 soon!

Getting dependency injection to work for Entity Framework Core outside of a Razor .cs page

This is for ASP.Net Core 2.1 using Razor with Entity Framework Core.
I think the question is how to define ReadData in ConfigureServices method?
Have tried to look at this question DbContext Dependency Injection outside of MVC project, but still cannot get code to work.
Trying to set up database access with Entity Framework Core through another class other than the Razor page.
In the Startup class in the ConfigureServices method we have this (I think this sets up the dependency injection for the Constructor in the Razor pages .cs):
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
//Add Dependency Injection references
services.AddScoped<IReadData, ReadData>();
This is a Razor .cs page and it works with the Constructor; however, we would want to separate the db look up into another class called ReadData.
public class MyPageModel : PageModel
{
private readonly MyProject.Data.AppDbContext _context;
private readonly ReadData readData = new ReadData();
public MyPageModel(MyProject.Data.AppDbContext context)
{
_context = context;
}
public IList<Car> Cars { get;set; }
public async Task OnGetAsync()
{
var userName = User.FindFirst(ClaimTypes.Name).Value; // will give the user's userName
Prayer = await readData.FetchCars(userName);
}
}
Here's the ReadData class:
public class ReadData : IReadData
{
private readonly MyProject.Data.AppDbContext _context;
public ReadData(MyProject.Data.AppDbContext context)
{
this._context = context;
}
public async Task<IList<Car>> FetchCars(string carOwner)
{
var cars = _context.Cars.Where(p => p.Owner == carOwner);
return await Task.FromResult(cars.ToList());
}
}
The dependency injection that works on the Razor .cs pages will not work here.
For example, in MyPageModel for this line:
private readonly ReadData readData = new ReadData();
it complains that a parameter is not assigned for the required parameter for ReadData class.
BUT, in ReadData if we add chaining constructor like this:
public ReadData() : this(new MyProject.Data.AppDbContext()) { }
we get an error:
InvalidOperationException: No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for DbContext.
How do we get dependency injection to work for Entity Framework Core in the ReadData class?
Your ReadData class should take a context in it's constructor:
public ReadData(MyProject.Data.AppDbContext context)
{
}
And now you only need to inject this class into your model:
public class MyPageModel : PageModel
{
private readonly IReadData _readData ;
public MyPageModel(IReadData readData)
{
_readData = readData;
}
public async Task OnGetAsync()
{
var userName = User.FindFirst(ClaimTypes.Name).Value; // will give the user's userName
var Prayer = await _readData.FetchCars(userName);
}
}
Let the DI container deal with creating your objects for you.
Just inject IReadData on the constructor of MyPageModel
public class MyPageModel : PageModel
{
private readonly MyProject.Data.AppDbContext _context;
private readonly IReadData _readData ;
public MyPageModel(IReadData readData)
{
_readData = readData;
}
public async Task OnGetAsync()
{
var userName = User.FindFirst(ClaimTypes.Name).Value; // will give the user's userName
var Prayer = await _readData.FetchCars(userName);
}
}
Don't create instance of ReadData
ReadData readData = new ReadData();
let DI container resolve your dependencies as you registered services.AddScoped<IReadData, ReadData>();

How to Pass Argument to constructor dynamically using structureMap

please note that this is my first project with DI and IoC thank you for all your help.
I am creating a multitenant app, were the application db context change from one tenant to another by providing a dynamic connection string.
while initialize the controllers and providing the connection string to the DAL class i am getting "String connectionString = Required primitive dependency is not explicitly defined"
DbContext:
public partial class DataContext : DbContext
{
public DataContext(string connectionString)
: base(connectionString)
{
}
// rest of the code ....
}
DAL:
public class ManagerDAL : IEntityRepository<TestManager>
{
private readonly DataContext _context;
public ManagerDAL(string connectionString)
{
_context = new DataContext(connectionString);
}
// rest of the code
}
Controller:
public class TestController
{
private ManagerDAL _managerDAL;
// .... different DAL
public TestController()
{
_managerDAL = new ManagerDAL("ConnectionString");
}
// reset of the code
}
Please any help would be much appreciated thank you.

Access DBContext using EF7 and VNext

In my MVC 6 project I have my ApplicationDBContext class
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
protected override void OnModelCreating(ModelBuilder builder)
{
}
}
This is added to my services in the Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
//Other configurations removed for brevity
}
Now when I create a new Controller, it asks me if I want to use the Entity Framework, and I can choose my data context. When that controller is created the context is passed in the constructor using what I assume is dependency injection.
public class CompanyController : Controller
{
private ApplicationDbContext _context;
public CompanyController(ApplicationDbContext context)
{
_context = context;
}
}
Now, I don't want to do all database interactions in the controllers, but rather in my other classes. What I can't figure out, is how to get the ApplicationDbContext from my other classes. Passing it from the controller obviously won't work because classes could be called from other places than the controller.
If I just try new ApplicationDbContext(); I get the following error:
No database providers are configured. Configure a database provider by overriding OnConfiguring in your DbContext class or in the AddDbContext method when setting up services.
I feel like this should be something simple, but I am completely lost here.
ASP.NET Core is based on dependency injection, since your context has been added in your dependendy container, it's automatically injected by the framework when your controller is instanciated.
Edit based on comments :
You can setup your classes to support DI, let's suppose you have two class. One that depend on your context, and then second that depend both on your context and your first class :
public class MyClass
{
private ApplicationDbContext _context;
public MyClass(ApplicationDbContext context)
{
_context = context;
}
}
public class AnotherClass
{
private ApplicationDbContext _context;
private MyClass _myClass;
public AnotherClass(ApplicationDbContext context, MyClass myClass)
{
_context = context;
_myClass = myClass;
}
}
Add your classes as a transient dependency in the sevice collections at startup, and let the service provider resolve their dependencies for you :
public void ConfigureServices(IServiceCollection services)
{
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
services.AddTransient<MyClass>();
services.AddTransient<AnotherClass>();
//Other configurations removed for brevity
}
Change your controller to accept MyClass as injected dependency :
public class CompanyController : Controller
{
private ApplicationDbContext _context;
private MyClass _myClass;
public CompanyController(ApplicationDbContext context, MyClass myClass)
{
_context = context;
_myClass = myClass;
}
}
You can also have another controller that take AnotherClass as injected dependecy :
public class AnotherController : Controller
{
private AnotherClass _anotherClass;
public AnotherController(AnotherClass anotherClass)
{
_anotherClass = anotherClass;
// _anotherClass will have both ApplicationDbContext and MyClass injected by the service provider
}
}
You should read the docs of dependency injection of ASP.NET Core, it could help to understand basics of DI. Another article from K. Scott Allen that explain some bad practice when you deal with DI.
You can create a service class that receives the DbContext in the same way as the controller.
public class SomeService
{
private ApplicationDbContext MyDbContext { get; set; }
public SomeService(ApplicationDbContext dbContext)
{
MyDbContext = dbContext;
}
public void MethodName()
{
// You can now do MyDbContext.SomeDomainModel
}
}
Then register the service in Startup.cs, in your ConfigureServices method.
public void ConfigureServices(IServiceCollection services) {
// <snipped>
services.AddTransient<SomeService>();
}
And now, in your CompanyController, you can add another parameter in the constructor for the SomeService, just as you have for the ApplicationDbContext.
public class CompanyController : Controller
{
private ApplicationDbContext _context;
private SomeService _someService;
public CompanyController(ApplicationDbContext context, SomeService someService)
{
_context = context;
_someService = someService;
}
}
All that said, I don't think there's anything wrong with doing your logic in your controller actions to build your ViewModel, accessing the DbContext. The DbContext is what's separating your business logic (in the controller) from the DAL. Some may disagree with me, but you don't need to add additional services to further separate them. Most of the code in your action methods are unique to that action and not going to be reused by other actions. IMO, those are the pieces of code to put into services. Things like sending emails and such.

Categories

Resources