It is not unusual to create a single ObjectContext
per web request. I do this in my web applications. However, IMO, the page should know nothing about the ObjectContext
.
Since you are already talking about injecting the context in the constructor of the service, take a look at dependency injection (if you aren't using that already). When you use a dependency injection container, you can let the container create that service for you and inject the object context in that container. The only thing your page has to do is request that service from the container (ideally, you would even let that service be injected in the constructor of that page, but this is not possible with web forms).
Your page would look like this:
public class MyPage : Page
{
private readonly IMyService service;
public MyPage()
{
this.service = Global.GetInstance<IMyService>();
}
protected void Btn1_OnClick(object s, EventArgs e)
{
this.service.DoYourThing(this.TextBox1.Text);
}
}
In the startup path (Global.asax) of your application, you can configure the Dependency Injection framework like this:
private static Container Container;
public static T GetInstance<T>() where T : class
{
return container.GetInstance<T>();
}
void Application_Start(object sender, EventArgs e)
{
var container = new Container();
string connectionString = ConfigurationManager
.ConnectionStrings["MyCon"].ConnectionString;
// Allow the container to resolve your context and
// tell it to create a single instance per request.
container.RegisterPerWebRequest<MyContext>(() =>
new MyContext(connectionString));
// Tell the container to return a new instance of
// MyRealService every time a IMyService is requested.
// When MyContext is a constructor argument, it will
// be injected into MyRealService.
container.Register<IMyService, MyRealService>();
Container = container;
}
In these examples I used the Simple Injector dependency injection container, although any DI container will do. The RegisterPerWebRequest
is not part of the core library, but is available as (NuGet) extension package. The package ensures that your ObjectContext
is disposed when the web request ends.
This might seem complex at first, but this way the web page doesn't have to worry at all about any details of creating and disposing an ObjectContext
.
Further, place the logic that executes a use case in a single class: a command. Let the command (or the system) ensure atomicness of that operation. Don't let the page be responsible for this, and don't commit on the end of the request, because at that point you won't know if it is even OK to call commit. No, let the command handle this itself. Here is an article about writing business commands.
This advice holds for ASP.NET MVC as well, although you should not call Global.GetInstance<IMyService>()
inside the Controller's constructor, but simply use constructor injection (since MVC has great support for this) and use the MVC3 Integration package.
Also take a look at this Stackoverflow question, which talks about choosing between a IObjectContextFactory
or having a ObjectContext
per request.