Web应用程序中的单例模式

ryu*_*ice 11 .net c# singleton design-patterns

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

Aar*_*ght 13

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

在这种情况下,"单身人士"可能意味着许多不同的事物.是每个请求的单实例吗?每次会话?每个线程?每AppDomain(static实例)?所有这些的影响是显着的不同.

每个请求(存储在HttpContext)中的"单例" 都可以.不鼓励每个会话单身,但可以使其工作.每个线程的单例可能看起来有效,但很可能导致意外和难以调试的行为.每个应用程序或AppDomain的单例是等待发生的灾难.

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

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

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

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

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

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

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

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

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

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


Luh*_*ann 8

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

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


Jul*_*iet 7

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

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

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

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

另外,如果你在静态变量中有状态信息,你需要某种类型的同步来修改它,否则你将会遇到种族条件的噩梦来解开.