2011-12-12 96 views
3

背景/问题:C#类库 - Singleton设计模式

我是相当新的Singleton设计模式。我已经在Web应用程序中使用一次(与SO社会的帮助下):

public static AppGlobal Instance 
{ 
    get 
    { 
     if (HttpContext.Current.Session != null) 
     { 
      HttpSessionState session = HttpContext.Current.Session; 

      if (session["AppGlobalInstance"] == null) 
      { 
       session["AppGlobalInstance"] = new AppGlobal(); 
      } 

      return (AppGlobal)session["AppGlobalInstance"]; 
     } 
     else 
     { 
      return null; 
     } 
    } 
} 

上述实施对我来说很有意义,因为AppGlobal的实例存储在会话中。当会话消失时,AppGlobal死亡。如果我在由Web应用程序调用的类库中使用相同的设计模式,会发生什么情况?例如,用户请求一个调用不知道会话的DLL中的方法的页面。存储在单例实例中的数据是否会通过多次调用持续存在?

private static readonly Singleton instance = new Singleton(); 
private Singleton() { } 

public static Singleton Instance 
{ 
    get 
    { 
     return instance; 
    } 
} 

附加信息:

这里就是我要完成的:我有一个要接收来自第三方应用XML请求的Web应用程序。这个XML将告诉我的Web应用程序执行三件事中的一件(或全部三件)。我想有一个类的单例实例存储可以被多个类访问的数据。我希望每个请求后单例实例到DIE。如果上述内容没有完成这个,那么完成它的最好方法是什么?

注意:此Web应用程序在单个服务器上运行,并且从不在服务器场上运行。

编辑1:

基于下面的建议下,我用System.Web.HttpContext.Current.Session来存储我的类的实例。这看起来像是对每个会话都是独一无二的单身人士的正确方法吗(记得我在一个班级图书馆里)?

public static Ariba Instance 
    { 
     get 
     { 
      if (HttpContext.Current.Session != null) 
      { 
       HttpSessionState session = HttpContext.Current.Session; 

       if (session["AribaInstance"] == null) 
       { 
        session["AribaInstance"] = new Ariba(); 
       } 

       return (Ariba)session["AribaInstance"]; 
      } 
      else 
      { 
       return null; 
      } 
     } 
    } 
+0

你提到你希望在每个**请求**后单身死亡。如果是这样的话,你不需要在会话中存储任何东西。相反,您可以将对象存储在HttpContext.Current.Items [“AribaInstance”]中。我会补充一点,如果你使用HttpContext.Current,你将会遇到一些单元测试你的类库的困难,因为HttpContext.Current不会被填充到ASP.NET之外(Session也是如此)。如果单元测试对你很重要,你需要包装上下文和会话对象。 –

+0

@AndyWilson,谢谢你的领导,并为答案! –

回答

4

它将通过多次调用持续,但有一个警告。静态变量的作用域为AppDomain,所以任何时候IIS工作进程被回收时,存储在静态变量中的任何数据都将丢失。会话数据也是如此,如果您将它存储在“proc”中。

如果您想要一个仅在HTTP请求期间存在的对象,则可以使用HttpContext.Items属性。

0

因为单是静态的,您的数据将可用于在Web应用程序的所有请求,所以它不会只为会议提供。

但是在ASP.NET应用程序中,您应该避免使用单例。相反,你应该使用Application对象。主要的原因是,如果你将使用一个网络农场,那么你的单例不再是应用程序范围的singelton,而只是在机器上。

+0

你在农场中使用应用程序状态的想法是错误的,你的意思是会话状态? – felickz

+0

_Scalability_ - **应用程序状态不在服务于同一应用程序的多个服务器之间共享,例如在Web场中,或在Web服务器中为同一台服务器上的同一应用程序提供服务的多个工作进程之间共享。因此,您的应用程序不能依赖包含不同服务器或进程中应用程序状态相同数据的应用程序状态。如果您的应用程序将在多处理器或多服务器环境中运行,请考虑使用更具可扩展性的选项(例如数据库),以获取必须保持整个应用程序保真度的数据。** – felickz

+0

[MSDN ASP.NET应用程序状态概述]( http://msdn.microsoft.com/en-us/library/ms178594.aspx) – felickz

0

哦! 如果您想使用PER REQUEST实例,为什么不将它作为参数传递给您正在调用的方法,或者将它作为需要xml的类的构造函数参数传递。我认为这将是最好的设计方法。

+0

我想过这个,但我不想添加8个参数到我创建的每个方法的签名。 –

+1

在这种情况下,就该开始考虑使用依赖注入了。大多数DI框架允许您使用“每个Web请求”生活方式配置对象,并将它们注入依赖它的类型中。这使您不必将它传递给调用堆栈中的所有方法(称为方法注入)。 – Steven

+0

好的。假设你不想将它们添加到构造函数中。您可以拥有一个拥有这8个依赖关系的类,并且只能通过签名中的那个类。使用这种方法可以很容易地对它进行单元测试。如果您想继续粘贴某种“静态”方式来获取它们,您需要将对象放在HttpContext.Current.Items集合中:public static MyObject {get {return(MyObject)HttpContext.Current.Items [ “MyObject”];} set {HttpContext.Current.Items.Add(“MyObject”,value); }} HttpContext.Current.Items是一个只存在于请求中的字典。 – ivowiblo