Ramifications of using DBContext with Dependency Injection - c#

I'm still kind of new to using dependency injection to manage my DBContext in an ASP.NET MVC application I'm writing.
I'm attempting to follow the approach outlined in the article Managing Entity Framework DbContext Lifetime in ASP.NET MVC. Basically, this approach says to use Ninject and dependency injection and to add my DBContext as a parameter to the constructor in my controllers.
Further, I am implementing this in a base controller, or which all my controller classes will be derived.
This is working, but I'm hitting on the following issues.
This approach requires that every derived controller class also implements a constructor that accepts any arguments requires by my controller base class. Not only does this seem like a lot of extra typing that I must remember to add to any new derived class, but it also means that if I change the data passed to the constructor then I must modify the constructor in every derived controller class.
This gives me a DBContext for all my controller classes. But what about other classes in my model that need the DBContext? Should I need to manually pass the instance to the DBContext to all these classes? Or is there a way to use DI for each of these classes to get their own copy of the DBContext?

This approach requires that every derived controller class also
implements a constructor that accepts any arguments requires by my
controller base class. Not only does this seem like a lot of extra
typing that I must remember to add to any new derived class, but it
also means that if I change the data passed to the constructor then I
must modify the constructor in every derived controller class.
This is one of the approach (Heavy Controller) that you may choose to use EF into your application, IMO its not the cleanest approach. And you correctly noticed the drawbacks your self.
If we relate this approach to design principle, it breaks Single Responsibility Principle as controller is expected to do more (fetch or update DB) than just collecting the data and return the appropriate view with data. And how about business rules, would controller apply it, if you need to send an email, would controller does that as well. You ought to have another layer of business/service classes that are specifically designed for a set of requirement e.g. EmailHelper would send emails.
It also breaks Open Close Principle as you need to change the constructors every time you change the input parameter.
This gives me a DBContext for all my controller classes. But what
about other classes in my model that need the DBContext? Should I need
to manually pass the instance to the DBContext to all these classes?
As far as dependency injection is concerned one of the goal is, to inject the dependency where it is needed directly. If you have a model class that needs DbContext, you should inject it in your model class constructor (most DI framework support property injection as well but constructor remains favourite approach).
With DI Framework, you will configure the dependencies at one place (application initialization code) and then each class that need a dependency just accept it in constructor.
DI Container can be compared to a dictionary where key is interface and the value is a cooked object. Once its setup, you can anytime ask for any object by using the right key through out your application.
Or is there a way to use DI for each of these classes to get their own
copy of the DBContext?
The DI framework supports different ways of instantiation to allow controlling the lifetime of the instance. Typically, per request, per thread and singleton. More information here. If you want each controller to get a copy of DbContext, you can use per request configuration when you set up DbContext instantiation.
Alternate Solution:
Most of my MVC applications, I have had a service layer (set of classes that apply business rule). Each of these classes were injected with DbContext (not exactly a DbContext but IDataContext). The controllers were injected with the service class that they need to retrieve or update the data.
Have abstracted the DbContext behind IDataContext, I could setup a stub data context in my test or tomorrow if I want to switch from EF to NHibernate or something more smart DI Framework, i will just have to implement IDataContext and change the dependency initialization code.
Hope this helps.

Related

Repository Pattern with Dynamic Connection String Based on Database Values

I have been looking into updating an existing codebase to better follow design patterns, principals, handle unit testing, separating concerns, etc. I am new to implementing a lot of these concepts so I am still doing a lot of research and trying to see how they could be implemented in the current codebase.
Currently each business entity has its own vb file. Within that vb file contains the entity, entity collection, and entity dalc classes for that entity. If you want to perform a database operation on the entity you would do so by calling Enity.Save, Entity.Delete, etc. These methods on the entity class would create the entity dalc object and then call the Save, Delete, etc. method on the entity dalc object. The dalc would then call a Save, Delete, etc. stored procedure through a SqlHelper class that handles the low level stuff.
Each entity class requires a Location object to be passed into it's constructor. This object is used to know what database the user is logged into as well as create the appropriate connection string to the database. The databases all have the same schema; they just have different names and can live on different SQL instances. Basically each client has their own database and the Location object hits up a shared database to find out what SQL instance the client needs to connect to based on the client's name which is stored in a cookie.
I have been looking into a more Model/Repository/Service approach but the Location object is throwing me off, especially since it too needs to access the database to get the information it needs to create the correct connection string. The repository objects need the connection string, but all of the examples I have seen have it hardcoded in the class. I am thinking the repository objects will need to take in an interface of the Location object but I'm not sure if the MVC project would do that directly or pass it into the service objects and they would handle it. At what point does the Location object get created, since it too needs to access the database in order for it to create the connection string, how does it get created?
I am also not clear on how the MVC project would interact with the Service and Repository layers. It seems like everything should run through the service objects, but for testing you would want them to take in an interface for the repository. Doing this would mean the MVC project would need to pass in the repository object, but it doesn't seem like the MVC project should know about the repository objects. However, if you are just doing basic CRUD it seems like it would be simpler to have the MVC project directly call those methods on the repository objects instead of running them through a service object.
Here is an example of what I am currently looking into. The plan is to use ADO.NET and SQL Server for now but possibly switch to an ORM or even a different SQL backend in the future. I am hoping the Model/Repository/Service approach will make it easy to make those changes in the future so if not feel free to offer advice on that as well.
Project.Model
public class Person
{
public int Id;
public string Name;
}
Project.Repository
public class PersonRepository
{
public Person FindById(int id)
{
// Connect to the database based on the Location's connection string
}
}
Project.Service
public class PersonService
{
private IPersonRepository _personRepository;
// Should this even take in the repository object?
public PersonService(IPersonRepository personRepository)
{
_personRepository = personRepository;
}
// Should the MVC project call this directly on the repository object?
public Person FindById(int id)
{
return _personRepository.FindById(id);
}
}
Project.MCV
// I think the Location object needs to come from here, as the client name is
// in the cookie. I'm not sure how the controllers should interact with the
// service and repository classes.
I second #Christian's advice. Using an ORM will greatly simplify your interactions with the underlaying data store; and NHibernate is a great choice.
However, in your example, the common way to interact with the data layer from the presentation (aka ASP.NET MVC project) is to inject the service as a dependency for your controller.
There are several ways to do this, the simplest, most straightforward is to use a dependency injection framework (like Unity) to instantiate your services as you specify in the controller's constructor,
public class PersonController : Controller
{
private readonly IPersonService personService;
public PersonController(IPersonService personService)
{
this.personService = personService;
}
}
Another way is to implement your own ControllerFactory implementation and inject the required services as needed. It is a lot more work, but if you have the time, you can lear a ton about the over all flow of the ASP.NET MVC routing flow and a bit of DI itself.
In a DI framework you (mostly) register interfaces with concrete classes implementations, basically saying that when an instance of IPersonRepository is required, use a new instance of PersonRepositoryImpl. With these registration rules in place, the DI framework will then recursively instantiate each dependency as it appears in the class constructor.*
In other words, when you request an instance of PersonController, the DI framework will then try to create an instance of type PersonController; when it sees that the constructor required an argument of type IPersonService, it first tries to instantiate one based on the same rules. Thus, the process starts again until all dependencies have been resolved and injected into the constructor for PersonController,
resolve PersonController
-> construct PersonController(IPersonService personService)
-> resolve IPersonService with PersonService
-> construct PersonService(IPersonRepository personRepository)
-> resolve IPersonRepository with PersonRepository
-> construct PersonRepository() <- this one has no dependencies
And back up the stack until a new instance of PersonController is returned.
*For this to work you must have only one public constructor for the given class, where each argument is a dependency that needs to be resolved (your examples nailed this down). If the type of the dependency is not registered with the framework, the resolution will fail. If there are multiple public constructors, the resolution will also fail (there is no sure way to determine which one to use), unless you register which constructor should be used (usually using attributes, but it depends on the DI framework in place). Some DI frameworks (like Unity) might allow you to have no constructor at all (which defaults to an empty, parameterless constructor) and have dependencies as public properties marked with a dependency attribute. I suggest not to use this method as it provides no way of knowing from a consumer class what dependencies the class needs (without using Reflection to inspect all properties and see which ones are marked as dependencies), which will in turn cause a myriad of NullReferenceExceptions.

Pass EF context on a project with multiple layers

I have an application that is separated into 4 layers to keep code organized and be able to reuse it.
My layers are:
presentation layer: an mvc4 project
business layer: a c# library project whit the Business logic
Data layer: a c# library that contains all the linq to the db
model layer: a c# library that contains a edmx ef5 for my database
So the idea is that for each controller or our mvc project we have 1 business class and 1 data class. and if some functionality needs to make use of code on other class, they do at business logic layer (different business logic classes can create new instances of other business logic classes.)
The problem I was having is that I was creating too many DbContext and I was getting some errors and problems because of it. Like loosing the lazy loading on my BL layers or not been able to assign objects like list to other objects when they came from different DbContext.
For example, if I have a medic controller/logic/data and I use a patient logic/data to get a list of patient for today, I get an error when I try to do medic.patients = patienstList;
So what I need to do is use one DbContext per web request, so the DbContext will be created on the controller and injected to the logic layer and those will inject to other logic class or to the data classes?
How can I do it?
There are number of ways of doing IOC in MVC.
Example would Unity.. where you can register an instance of DBContext.
Of course if the lifetime of you IOC container every extends beyond web requests. your are in for nasty time.
Even if you think it is 1 Context per request that you need. Be very careful if you use ASP pipeline events and access DbContext, you may actually need 1 context per Thread. But if you are happy to say you access starts at MVC Controller level. Then you are looking for a way to handle inversion of control only.
Unity from microsoft
dependency injection docu
https://unity.codeplex.com/documentation
IMHO the Business Object should not have to use another Business Object because that violates the Single Responsibility Principle.
The Data Layer object should be able to do everything the Business Object needs it to.
So you should write methods in the Business Layer Object and Data Layer Object method GetPatientsForMedic.
You may say "but the Hospitals Business Object can get me a list of Hospitals really easily". That is not it's job, because you said it's job is to service the Hospitals controller.
HOWEVER the problem only happens when you pass a Hospital object from the HospitalsBO to the MedicBO. So don't.
On the Hospitals controller, write a method GetListOfHospitalIDsAndNames. Then, if you need a dropdown of hospitals, call that, and use the IDs and text names.
You can indeed share a DbContext between two Business Objects by sharing a Unit of Work. But you probably shouldn't.
However i'm no expert... i avoided these problems by having one GINORMOUS business object with everything in it. That is also a BAD THING.

Structure for switchable Data Access Layer

I need to write a Data Access Layer using Entity Framework. One of the requirements is to allow a configuration file to control where the data comes from. With one config setting it should come from a database; with another, from a web service.
Now, my initial thought is to have 3 DataAccess classes:
WidgetDataAccess
WidgetDatabaseDataAccess
WidgetWebServiceDataAccess
They would all implement the same interface. WidgetDataAccess would read the config and delegate to the correct child class. That seems sensible, right?
Is there any pattern that I should follow, or anyone with a better way to structure this?
Yes, Repository / UnitOfWork pattern.
Widget.Core : Your MVC application using only Widget.DAL namespace, dependency injected with either Widget.DAL.DatabaseService or Widget.DAL.WebService based on your config file
Widget.DAL : IRepository, IUnitOfWork, IWhateverYouNeed, DTOs
Widget.DAL.DatabaseService : Entity Framework Models and Context. Implementation of Widget.DAL interfaces using your Entity Framework context
Widget.DAL.WebService : Web client, Domain objects, implementations of Widget.DAL interfaces using your Web client

asp.net mvc3 Code First (Database Singleton)

I am working on asp.net mvc using code first. I noticed that once i create a new controller, the controller template shows dispose overridden method that just has one job; dispose db variable created at the top of this controller.
I am thinking of changing this to use singleton pattern with my DBContext class.
I tried it and it worked fine. except that i needed sometimes to access database from global.asax. (sometimes) is throws an exception.
Have anyone thought to do the same? Any ideas?
Thank you
personally I would follow a completely different approach, see my answer here: https://stackoverflow.com/a/7474357/559144 I would not use Singleton and would not hardlink MVC which is a UI framework with the DAL (EF in your case).
about not using singleton, let the database handle concurrency; it's one of the things Database servers do the best ;-)
We use EF context as a singleton per http context. I also would not hard link EF with MVC, but you can still be sure that each http context deals with a single EF context instance by using dependency injection (we use Unity).
We also access the context in global asax to do db initialization and seeding for development. Again, you can use a DI container to get an instance of the EF context.
public interface IUnitOfWork : IDisposable
{
int SaveChanges();
}
public class MyEfContext : DbContext, IUnitOfWork
{
// your custom context code
}
Using a singleton-per-http-context lifetime for the IUnitOfWork dependency injection isn't an approach to help deal with concurrency in our case. We do it because when dealing with EF entities, we need to make sure all of the selects / inserts / updates / deletes always happen with the same context instance. EF does not let you attach entities to multiple contexts, and we use singleton per http context for this reason.

Entity Framework 4 ObjectContext GuideLines

I read in a previous article about how to resolve a solution by placing the ObjectContext of my Db in a property within HttpContext.Current.Items["Db"]; This works fantastic, however I have a question. Does this means that every time I use my repository I have to pass the ObjectContext within HttpContext.Current.Items or do I only need to do this when I am creating or updating an entity that has a reference to another entity.
Within my repository classes I have 2 ways of instantiating them, with a ObjectContext and without one in which the ObjectContext is created there within the entity.
You should share one context among all your repositories used in single HTTP request processing. You should also dispose context at the end of request processing. Generally your repository should not be dependent on HttpContext. The best way is to create ObjectContext outside of your repositories and always pass it to their constructor. You can also do that by using some IoC container like Windsor, StructureMap, Ninject or Unity.

Categories

Resources