ASP MVC Entity Framework Database context and classes - c#

In my asp mvc Framework project, using EF, I have some objects (from classes) whose fields store data coming from my database.
My question is :
How to populate these fields, or manage methods of these objects using a dbcontext variable ?
Sol 1: Is it better to use each time I need a connection with db in my classes with the instruction (using (resource), see below ) ?
Sol 2: Is it betterI to code a singleton class to use one instance of the context ?
Sol 3: Or should I use another way for the links beetween my classes and the database ?
What is the best method considering performances and code quality.
Thanks for your attention .
Solution 1
public class Test
{
private T1 a;
private T2 b;
public Test()
{}
public void CreateFrom (int id)
{
using (var db=new WebApplicationMVCTest.Models.dbCtx())
{
a=db.T1s.Find(id);
b= db.T2s.Find(a.id2);
}
}
Solution 2:
public class DbSingleton
{
private static dbCtx instance;
private int foo;
private DbSingleton ()
{}
public static dbCtx Current
{
get
{
if (instance == null)
{
instance = new dbCtx();
}
return instance;
}
}
public static void Set (dbCtx x)
{
if (instance==null)
{
instance = x;
}
}
}

For a web project, never use a static DbContext. EF DbContexts are not thread safe so handling multiple requests will lead to exceptions.
A DbContext's lifespan should only be as long as it is needed. Outside of the first time setup cost when a DbContext is used for the first time, instantiating DbContexts is fast.
My advice is to start simple:
public ActionResult Create(/* details */)
{
using (var context = new AppDbContext())
{
// do stuff.
}
}
When you progress to a point where you learn about, and want to start implementing dependency injection applications then the DbContext can be injected into your controller / service constructors. Again, from the IoC container managing the DbContext, the lifetime scope of the Context should be set to PerWebRequest or equivalent.
private readonly AppDbContext _context;
public MyController(AppDbContext context)
{
_context = context ?? throw new ArgumentNullException("context");
}
public ActionResult Create(/* details */)
{
// do stuff with _context.
}
The gold standard for enabling unit testing would be injecting a Unit of Work pattern and considering something like the Repository pattern to make your dependencies easier to unit test.
The best advice I can give you starting out with EF and MVC is to avoid the temptation to pass Entities between the controller (server) and the UI. (views) You will come across dozens of examples doing just this, but it is a poor choice for performance, it also hides a LOT of land mines and booby traps for both performance, exceptions, and data security issues. The most important detail is that when the UI calls the controller passing what you expect will be an entity, you are not actually getting an entity, but a de-serialized JSON object cast to an entity. It is not an entity that is tracked by the DbContext handling the request. Instead, get accustomed to passing view models (serializable data containers with the data the view needs or can provide) and IDs + values where the controller will re-load entities to update the data only as needed.

Related

How to dispose the ContextDB class automatically after any query done using it

ASP.NET MVC 5 Project.
I know that the best practice of using EF context object as the following
using(var context = new ContextDB())
{
}
But I am working with a large existing project which not used this practice.
the project using the following pattern
public abstract class BaseService
{
private static ContextDB _data { get; set; }
public static ContextDB Data
{
get
{
if (_data== null)
_data= new ContextDB();
return _data;
}
}
}
Actually, because of this pattern, I am receiving this exception (sometimes, not always)
So to solve this I have to change all the code which is using the shared Data
property and replace it with the new instance of ContextDB as I mentioned in the beginning of the question.
The problem that this is a very large modification, and I will not be allowed to do that modification.
The Question, can I solve this problem without changing a ton of code, In another word, can I solve the problems with modifications done only inside the BaseService class, for example, Is there any event which I could handle to know if any query is executed and then dispose of the ContextDB
here is the pseudo-code of the idea in my mind
public abstract class BaseService
{
public static ContextDB Data
{
get
{
ContextDB _data= new ContextDB();
_data.SqlQueryExecuted += () => { this._data.dispose(); }
return _data;
}
}
}
NOTE: the SaveChanged event is not suitable, because not all of the query are updating or inserting.
I may use following solution.
In Global.asax
Begin Request : Create Instance of your dbContext. Store it in HttpContext.Current.Items.
End Request : Grab the context and close / dispose connection.
Another better solution is to use DI. Dependency Injection and limit the scope of your instance. There are many way Like Singleton, PerRequest etc.

How to handle on-demand data fetching for Domain Models

Given the following scenario...
I am concerned about two things...
1) Is it okay to inject a provider into a business model object? - like I did with the Folder implementation because I want to load Sub-folders on demand.
2) Since I am injecting the DbContext in the Sql implementation of IFolderDataProvider, the context could be disposed or it could live on forever, therefore should I instantiate the context in the constructor?
If this design is incorrect then someone please tell me how should business models be loaded.
//Business model.
interface IFolder
{
int Id { get; }
IEnumerable<IFolder> GetSubFolders();
}
class Folder : IFolder
{
private readonly int id_;
private readonly IFolderDataProvider provider_;
public Folder(int id, IFolderDataProvider provider)
{
id_ = id;
provider_ = provider;
}
public int Id { get; }
public IEnumerable<IFolder> GetSubFolders()
{
return provider_.GetSubFoldersByParentFolderId(id_);
}
}
interface IFolderDataProvider
{
IFolder GetById(int id);
IEnumerable<IFolder> GetSubFoldersByParentFolderId(int id);
}
class SqlFolderDataProvider : IFolderDataProvider
{
private readonly DbContext context_;
public SqlFolderDataProvider(DbContext context)
{
context_ = context;
}
public IFolder GetById(int id)
{
//uses the context to fetch the required folder entity and translates it to the business object.
return new Folder(id, this);
}
public IEnumerable<IFolder> GetSubFoldersByParentFolderId(int id)
{
//uses the context to fetch the required subfolders entities and translates it to the business objects.
}
}
Is it okay to inject a provider into a business model object? - like I did with the Folder implementation because I want to load Sub-folders on demand.
Yes, how else would you be able to call the provider and get the data?
However, the suffix DataProvider is very confusing because it is used for the provider that you use to connect to the database. I recommend changing it to something else. Examples: Repository, Context.
Since I am injecting the DbContext in the Sql implementation of IFolderDataProvider, the context could be disposed or it could live on forever, therefore should I instantiate the context in the constructor?
It won't necessarily live on forever. You decide its life span in your ConfigureServices function when you're adding it as a service, so you can change its scope from Singleton to whatever you like. I personally set the scope of my DBContext service to Transient and I also initiate it there with the connection string:
services.AddTransient<IDbContext, DbContext>(options =>
new DbContext(Configuration.GetConnectionString("DefaultDB")));
I then open and close the database connection in every function in my data layer files (you call it provider). I open it inside a using() statement which then guarantees closing the connection under any condition (normal or exception). Something like this:
public async Task<Location> GetLocation(int id) {
string sql = "SELECT * FROM locations WHERE id = #p_Id;";
using (var con = _db.CreateConnection()) {
//get results
}
}
Is it okay to inject a provider into a business model object
Yes if you call it "business" provider :). Actually do not take too serious all this terminology "inject", "provider". Till you pass (to business model layer's method/constructor) interface that is declared on business model layer (and document abstraction leaks) - you are ok.
should I instantiate the context in the constructor?
This could be observed as an abstraction leak that should be documented. Reused context can be corrupted or can be shared with another thread and etc -- all this can bring side effects. So developers tend to do create one "heavy" object like dbContext per "user request" (that usually means per service call using(var context = new DbContext()), but not always, e.g. Sometimes I share it with Authentication Service Call - to check is the next operation allowed for this user). BTW, DbContext is quite quick to create so do not reuse it just for "optimization".

What is best practice for using Unity with Entity Framework in a MVC 4 application

I'm struggling with Entityframework in a MVC 4 app, making use of Unity for Dependency injection and Automapper for automapping object to DTO. I run from one issue to the other, EF is sometimes returning old data, so I think my design is not good enough.
What do I have:
To configure Unity I have in my Application_Start:
var UnityContainer = UnityConfig.GetConfiguredContainer();
Mapper.Initialize(cfg => cfg.ConstructServicesUsing(type => UnityContainer.Resolve(type)));
UnityContainer.Resolve<AutoMapperConfig>().MapAutoMapper();
...
In UnityConfig.RegisterTypes:
container.RegisterType<IMyContext, MyContext>(new ContainerControlledLifetimeManager())
...
My respositories use constructor depencency injection:
public class MSSQLTenantRepository : IDalTenantRepository
{
private readonly IMyContext _Db;
public MSSQLTenantRepository(IMyContext db)
{
Db = db;
}
...
And my controller use constructor dependency injection too:
public class TenantController : Controller
{
private readonly ITenantRepository _TenantRepository;
public TenantController(ITenantRepository tenantRepository,
{
_TenantRepository = tenantRepository;
}
...
Automapper config:
public class AutoMapperConfig
{
private readonly ITenantRepository _TenantRepository;
public AutoMapperConfig(ITenantRepository tenantRepository)
{
_TenantRepository = tenantRepository;
}
...
Issues:
I sometimes get old data, from the first request.
When I manually update the data in de SQL server, EF's returning object don't reflect the changes
When I tried different options I also got error about multiple context (due to Automapper)
My questions:
What is best practice using Unity, MVC4, EF 6, repositories and Automapper?
Where to put the code (e.g. in global.asax.c or in UnitiConfig.cs of UnityWebApiActivator?
Do I need to explicit dispose the dbcontext, and if so: Where to do this?
There is a lot said about this subject, but nothing covers all.
container.RegisterType<IMyContext, MyContext>(
new ContainerControlledLifetimeManager())
This is rather bad, it makes a singleton out of your context. This way not only multiple requests share the same context and you risk concurrency issues but also the memory consumption of such shared context grows without control.
Rather, you would like to have a "per-request" life time, where a new context is established for each separate request:
http://www.wiktorzychla.com/2013/03/unity-and-http-per-request-lifetime.html
public class PerRequestLifetimeManager : LifetimeManager
{
private readonly object key = new object();
public override object GetValue()
{
if (HttpContext.Current != null &&
HttpContext.Current.Items.Contains(key))
return HttpContext.Current.Items[key];
else
return null;
}
public override void RemoveValue()
{
if (HttpContext.Current != null)
HttpContext.Current.Items.Remove(key);
}
public override void SetValue(object newValue)
{
if (HttpContext.Current != null)
HttpContext.Current.Items[key] = newValue;
}
}
and
container.RegisterType<IMyContext, MyContext>(new PerRequestLifetimeManager())
I am not sure what your AutoMapperConfig class does and why a repository is injected into it. This is a possible another lifetime issue but I need a clarification on that.
I figured it out with some help of Wiktor.
First: I must just a PerRequestLifeTimeManager (as stated by Wiktor Zychla, thank you for that), which is available in de Unity for MVC bootstrapper.
Second: The line:
UnityContainer.Resolve<AutoMapperConfig>().MapAutoMapper();
must be in Application_BeginRequest (Globas.asax.cs). I've put it in Application_Start, so this was only resolved once at startup. An incoming request was creating a new context, so it differs from the one that Automapper uses. When putting it in BeginRequest the resolve is done on every request, with the same context as the repositories.

Using a DbContext variable from one Controller to Another

Hi I am using MVC 4 and C# to develop an application that has two controllers:
The first one is called Business, it has a method called Create that calls a method called CreatePartner from another Controller named PartnerController.
public class BusinessController : Controller
{
private storeContext db = new storeContext();
public ActionResult Create(Business business)
{
//Some stuff here
PartnerController pt = new PartnerController();
pt.CreatePartner(int partner_id);
//Here is another stuff that uses db DbContext variable
return RedirectToAction("Index");
}
}
This is the second controller Called Partner
public class PartnerController : Controller
{
private storeContext db = new storeContext();
public void CreatePartner(int partner_id)
{
//Some interesting stuff
}
}
Each controllers has its Dispose() method
The Problem is: After I called the CreatePartnet method from Business controller I try to use the db variable again to save other data but it throws me the following exception:
The operation can not be completed because the DbContext has been disposed
-What is the best way to Use methods from one controller to another that has the same DbContext variable name?.
-Something strange happens: My stuff works locally but when I publish my code in the IIS server is when the app throws that exception.
Thanks!
Might I suggest an alternative approach?
Controllers are not very good places for business logic; that is they're not very good places for "doing stuff". It's often demonstrated in MVC tutorials and examples in this manner but it's really only good for getting into MVC quickly - it's not very good practice.
Furthermore Controllers aren't really supposed to have methods to be called - from themselves or called from another Controller. Controllers should really just contain their Actions.
Instead, extract your logic to an external class. A Service is a design pattern in which commonly used business logic is abstracted away. That way things can have a reference to the service and execute the logic without knowing anything about the implementation.
Observe:
IPartnerService
public interface IPartnerService
{
void CreatePartner(int partnerId);
}
DefaultPartnerService
public class DefaultPartnerService : IPartnerService
{
private StoreContext db;
public DefaultPartnerService()
{
db = new StoreContext();
}
public void CreatePartner(int partnerId)
{
// Something interesting
}
}
BusinessController
public class BusinessController : Controller
{
private IPartnerService _partnerService;
public BusinessController()
{
_partnerService = new DefaultPartnerService();
}
public ActionResult Create(Business business)
{
_partnerService.CreatePartner(business.PartnerId);
return RedirectToAction("Index");
}
}
Of course this approach is also greatly simplified for educational purposes. It's not best practice yet, but it might put you on the right track. Eventually you'll discover problems with this approach and you'll gravitate to reading about Repositories, Unit of Work, Dependency Injection and so on.

Performance consideration of destroying dataContext vs. keeping it open for future db access?

I'm using LINQ2SQL to handle my database needs in a ASP. Net MVC 3 project. I have a separate model which contains all my database access in its own class as follows:
public class OperationsMetricsDB
{
public IEnumerable<client> GetAllClients()
{
OperationsMetricsDataContext db = new OperationsMetricsDataContext();
var clients = from r in db.clients
orderby r.client_name ascending
select r;
return clients;
}
public void AddClient(client newClient)
{
OperationsMetricsDataContext db = new OperationsMetricsDataContext();
db.clients.InsertOnSubmit(newClient);
db.SubmitChanges();
}
I have about 50 different methods in this class which all create and then destroy a copy of my DataContext. My reasoning was that this way would save memory because it would destroy the DataContext after I use the connection and free up that memory. However, I have a feeling that it may be better to use one copy the dataContext and keep it open instead of disposing and reestablishing the connection over and over again. e.g
public class OperationsMetricsDB
{
OperationsMetricsDataContext db = new OperationsMetricsDataContext();
public IEnumerable<client> GetAllClients()
{
var clients = from r in db.clients
orderby r.client_name ascending
select r;
return clients;
}
public void AddClient(client newClient)
{
db.clients.InsertOnSubmit(newClient);
db.SubmitChanges();
}
What is the best practice on this?
I personally use the Unit of Work pattern in conjunction with Repositories for this.
The UnitOfWork creates and manages the DataContext. It then passes the context to each repository when requested. Each time the caller wants to do a new set of operations with the database, they create a new UnitOfWork.
The interfaces would look something like:
public interface IUnitOfWork
{
IRepository<T> GenerateRepository<T>();
void SaveChanges();
}
public interface IRepository<T> where T : class
{
public IQueryable<T> Find();
public T Create(T newItem);
public T Delete(T item);
public T Update(T item);
}
That ensures that the context's lifespan is exactly one Unit of Work long (which is longer than a single operation but shorter than the lifespan of the application).
Its not recommended to cary a datacontext a long time with you. So you are on the right path. It uses connection pooling as far as i know, so the performance hit of creating more than one datacontext in an applications lifetime is not too serious.
But i would not create a new context instance for every single method call of your data class.
I prefer to use it in a unit of work style. Within a web application the processing of a http request can be seen as a unit of work.
So my advice is to create one datacontext instance for the lifetime of on http request and dispose it afterwards.
One context per request is usually fine for most applications.
http://blogs.microsoft.co.il/blogs/gilf/archive/2010/05/18/how-to-manage-objectcontext-per-request-in-asp-net.aspx

Categories

Resources