为每个 Web 请求创建一个 ObjectContext 并不罕见。我在我的 Web 应用程序中执行此操作。但是,IMO,该页面应该对ObjectContext 一无所知。
既然您已经在谈论在服务的构造函数中注入上下文,请看一下依赖注入(如果您还没有使用它)。当您使用依赖注入容器时,您可以让容器为您创建该服务并在该容器中注入对象上下文。您的页面唯一需要做的就是从容器中请求该服务(理想情况下,您甚至可以将该服务注入该页面的构造函数中,但这对于 Web 表单是不可能的)。
您的页面将如下所示:
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);
}
}
在应用程序的启动路径(Global.asax)中,您可以像这样配置依赖注入框架:
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;
}
在这些示例中,我使用了 Simple Injector 依赖注入容器,尽管任何 DI 容器都可以。 RegisterPerWebRequest 不是核心库的一部分,而是 is available as (NuGet) extension package。该包可确保您的 ObjectContext 在 Web 请求结束时被释放。
起初这可能看起来很复杂,但这样网页就不必担心创建和处置ObjectContext 的任何细节。
此外,将执行用例的逻辑放在一个类中:一个命令。让命令(或系统)确保该操作的原子性。不要让页面对此负责,也不要在请求结束时提交,因为那时您将不知道调用 commit 是否可以。不,让命令自己处理。这里是an article about writing business commands。
这个建议也适用于 ASP.NET MVC,尽管您不应该在 Controller 的构造函数中调用 Global.GetInstance<IMyService>(),而只需使用构造函数注入(因为 MVC 对此有很好的支持)并使用 MVC3 Integration package。
还可以查看this Stackoverflow question,它讨论了在IObjectContextFactory 或ObjectContext 之间进行选择。