Reputation: 746
My context is used in two controllers (AdminController
which can view and add some data and HomeController
which only views data).
Can I make my context class be just fields in my controllers classes? Or should I make it a singleton? Or should I create an additional singleton class which stores all DbContext
classes in my website? How should it be properly done?
Upvotes: 2
Views: 3762
Reputation: 44580
I believe that the best way for ASP.NET MVC would be to use 1 DbContext per Request. You will benefit from this approach because:
Of course you can use IoC containers, but I don't like the overhead because you can easily write all the necessary logic by yourself.
So we need a wrapper for DbContext
. It will keep your EF context in HttpContext items. In ASP.NET MVC app you can put the initialization in your base controller:
public class DbContextHelper : IDbContextHelper // interface for testing if you need it
{
private const string contextKey = "MyContext";
public MyContext GetContext()
{
if (HttpContext.Current.Items[contextKey] == null)
{
HttpContext.Current.Items.Add(contextKey, new MyContext());
}
return (MyContext) HttpContext.Current.Items[contextKey];
}
public void DisposeContext()
{
if (HttpContext.Current.Items[contextKey] != null)
{
var context = (MyContext) HttpContext.Current.Items[contextKey];
context.Dispose();
}
}
}
And now to complete the setup we need to inject DisposeContext
call into the End_Request event. It depends on which version of ASP.NET you use. Usually I create an ActionFilter that disposes context. And register it globally.
public class DisposeDbContextFilterAttribute : ActionFilterAttribute
{
private static readonly DbContextHelper contextHelper = new DbContextHelper();
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
contextHelper.DisposeContext();
}
}
Now, when everything is set up, just enjoy using it:
var user = contextHelper.GetContext().Users.Find(userId);
Upvotes: 3
Reputation: 1513
This is a good architectural question and here is an excellent resource you can review:
Personally, I would lean toward allowing your IoC container to manage creating the connections for you and injecting them into your controllers. Or, if you use a repository or similar architecture you could inject the context directly into those classes and inject your repositories into your controllers.
If that is too complex for your application, you won't have serious performance issues using either of the other methods in the example link. Entity will utilize connection pooling so there isn't as much overhead.
I wouldn't want my context to be a singleton as I'd want each web request to contain its own context object. There are a lot of reasons for this, not the least of which is performance if you leave on tracking. A singleton context could also leave the door open to strange transaction issues -- remember that web is a multi-threaded environment.
Remember, there is no right or wrong answer necessarily as you're asking an architecture question and not one architecture works for every single application. If your solution is easy to understand, easy to maintain, and utilizes best practices then you are doing a good job.
Hope this information helps and good luck!
Upvotes: 1
Reputation: 218722
Can I make my context class be just fields in my controllers classes?
Sure. you can create a private field in your controller to keep the instance of your db context class.
You do not need to make it singleton. The requests coming to your AdminController and HomeController are 2 different HTTP requests and it should create & use a new object of your DbContext class for every http request..
public class AdminController
{
private YourDbContext db;
public AdminController()
{
db = new YourDbContext();
}
public ActionResult Users()
{
var list=db.Users.ToList();
//use list as needed now
}
}
With this approach, only problem is, you will create an object of YourDbContext even if you are requesting an action method which is not using any data.
If needed, you can create a YourBaseController and create the DbContext object initialization there and both of your controllers can inherit from that.
public class MyBaseController : Controller
{
protected YourDbContext db;
public MyBaseController ()
{
db = new YourDbContext();
}
}
public class AdminController : MyBaseController
{
}
Since you are not disposing the DbContext object from memory, We will be relying on the dot net Garbage collector.
But if you want, you can create an object of your DbContext class, use it and dispose it after use by making use of the using
keyword
public ActionResult View()
{
var name= new List<string>();
using(var db=new YourDbContext())
{
name=db.Users.Select(s=>s.Name);
}
//to do : return something
}
with the use of using expression, the framework will dispose the YourDbContext instance once it exits the scope of the using { }
Also, it might be a good idea to look into dependency injection so that you won't create your objects using new
keyword manually ,but the framework will inject those for you. This will help you to make your code more unit testing friendly.
Upvotes: 0