Web应用程序中的单例模式

我在我的Web应用程序中使用单例模式作为datacontext,因此我不必每次都实例化它,但是我不确定Web应用程序是如何工作的,IIS是否为每个连接的用户打开一个线程? 如果是这样,如果我的单例不是线程安全会发生什么? 另外,对于datacontext使用单例模式是否可以? 谢谢。

许多人在请求期间保留DataContext,方法是将其保存在HttpContext.Current.Items因此,它也是请求的私有。

看看Steve Sanderson撰写的这篇博文 ,以及UnitOfWork模式 。

我在我的Web应用程序中使用单例模式作为datacontext

在这种情况下,“单身人士”可能意味着许多不同的事物。 是每个请求的单实例吗? 每次会话? 每个线程? 每个AppDomain( static实例)? 所有这些的含义是截然不同的。

每个请求(存储在HttpContext )的“单例”都可以。 不鼓励每个会话单身,但可以使其工作。 每个线程的单例似乎可以工作,但可能会导致意外和难以调试的行为。 每个应用程序或AppDomain的单例是等待发生的灾难。

所以我不必每次都实例化它

创建DataContext非常非常便宜。 元数据是全局缓存的,在实际执行查询之前不会创建连接。 没有理由尝试优化DataContext实例的构造。

但是我不确定Web应用程序是如何工作的,IIS是否为每个连接的用户打开了一个线程?

IIS为每个请求使用不同的线程,但是单个请求可能使用多个线程,并且线程从线程池中获取,这意味着最终同一个用户将在许多不同的线程上发出请求,相反,不同的用户将共享多个请求和延长的时间段内的相同线程。 这就是为什么我在上面提到你不能依赖Thread-Local Singleton。

如果是这样,如果我的单例不是线程安全会发生什么?

很糟糕的事情。 您在ASP.NET应用程序中全局缓存的任何内容都需要设置为线程安全或需要在使用时锁定。

另外,对于datacontext使用单例模式是否可以? 谢谢。

DataContext不是线程安全的,在这种情况下,即使你在使用时锁定DataContext (这已经不是一个好主意),你仍然可以遇到跨线程/交叉请求竞争条件。 不要这样做。

应尽可能使用using子句将DataContext实例限制在单个方法的范围内。 接下来最好的事情是将它们存储在HttpContext 。 如果必须,您可以在Session中存储一个,但是您需要注意很多事情(请参阅我最近在ObjectContext上回答的这个问题 – 几乎所有相同的原则都适用于DataContext )。

但最重要的是, 不要在ASP.NET应用程序中创建DataContext “全局”单例实例。 你以后会后悔的。

每个应用程序域上的所有用户都可以看到静态变量,而不是每个会话。 一旦创建,变量将在应用程序域的生命周期内驻留在内存中,即使没有对该对象的活动引用也是如此。

因此,如果您在Web应用程序中有某些其他用户不应该看到的有状态信息,那么它绝对应该是静态的。 将这种信息存储在用户会话中,或将静态var转换为如下所示:

 public static Data SomeData { get { if (HttpContext.Session["SomeData"] == null) HttpContext.Session["SomeData"] = new Data(); return (Data)HttpContext.Session["SomeData"]; } } 

看起来像一个静态变量,但它的会话特定,因此当会话终止时数据被垃圾收集,而其他用户完全看不到它。 安全无法保证。

另外,如果你在静态变量中有状态信息,你需要某种同步来修改它,否则你将会遇到一个解决竞争条件的噩梦。

@ryudice Web服务器为每个请求创建一个新线程。 我认为最好的方法是将datacontext绑定到每个请求,这意味着每次提交请求时都应该创建一个新的datacontext。 实现这一目标的一个好方法是使用DI工具,例如StructureMap 。 这些工具允许您设置所配置实例的生命周期,因此在您的情况下,您可以将XDataContext类配置为HttpContext作用域。

问候。

以下是Microsoft关于如何使用LINQ-To-SQL执行多层的示例。

http://code.msdn.microsoft.com/multitierlinqtosql