【问题标题】:Singleton pattern in asp.netasp.net 中的单例模式
【发布时间】:2013-11-27 09:20:40
【问题描述】:

我有一个 asp.net 应用程序。我正在使用单例模式来设计我的代码。如下所示……

public static class FactoryClass
    {
        private static Core obj = null;
        private static readonly object padLock = new object();
        public static Core GetInstance()
        {
            lock (padLock)
            {
                if (obj == null)
                {
                    obj = new Core();
                }
            }
            return obj;
        }
    }

这个实现是线程安全的。我想知道这个实现是否正确,在 asp.net 的情况下(多个请求将共享一个实例)。请指教……

【问题讨论】:

  • 您在 asp.net 中制作静态单例的具体原因是什么?这门课有什么特别贵的东西吗?
  • 您是否缺少私有构造函数?
  • 作为一般性评论,我个人会在锁本身周围添加另一个if (obj == null)。如果它已经被实例化了,那么就没有必要承受锁定的影响了。你仍然需要内部的if,这样它就不会被多次创建,但是外部的可以在不需要时绕过整个过程。
  • 你还是不清楚。您是否希望用户共享数据?如果您想要在一个请求的整个生命周期内都存在的东西,请使用 HttpContext.Items。如果您想要在一个用户会话的整个生命周期内都存在的东西,请使用 Session。如果您想要单个服务器上的所有用户通用的东西,请使用静态 - 但要准备好处理所有相应的线程相关问题(许多请求可以同时访问该数据)。

标签: c# asp.net singleton


【解决方案1】:

您的单吨对象范围将在应用程序域内,这意味着所有会话都将使用该应用程序域内的 SingleTon 对象(默认情况下)。

仅当您的场具有不同的服务器时才会创建一个新对象。

我更喜欢只在你需要构造一个对象时才使用锁,而不是在你必须返回它时。以下是修改后的代码:

public static class FactoryClass
{
    private static Core obj = null;
    private static readonly object padLock = new object();

    public static Core GetInstance()
    {
        lock (padLock)
        {
          if (obj == null)
          {
                obj = new Core();
          }
        }
        return obj;
      }
}

【讨论】:

  • 在单例模式中使用私有构造器有什么用?
  • 我已经更改了代码,我知道你需要单核对象而不是工厂类。
  • 此实现不是线程安全的,因为它不能确保 null 测试和构造函数调用之间的原子性。你可以看看@HansKesting 指出的csharpindepth.com/articles/general/singleton.aspx
  • @ImranRizvi 好的。我想知道我们在 asp.net 中使用单例模式时是否会导致用户数据混淆问题。用户 1 获取用户 2 数据。就像静态变量一样。这也是我们正在使用静态成员
  • @anish SingleTon 确保该对象将在应用程序域内的多个会话之间共享,因此如果您返回非用户特定的数据(核心),显然会有混合。
【解决方案2】:

这取决于 Core 类型的对象中存储的数据类型。说它的一些配置数据,你想单独管理(即它与 web.config 中的那些完全不同),那么它是有意义的。

但是,假设网站是一个购物车应用程序...并且您希望像这样存储用户对象...假设用户对象包含他保存在卡中的项目列表。这将存储在 appdomain 中。因此,它与您的实施背道而驰。因为您希望您的用户信息与传入请求而不是整个应用程序相关联。因此,每个请求您都需要至少查询一次...(当然是传统意义上的)。

继续使用相同的示例,假设您想以这种方式使用用户对象:该用户对象在您的 Web 应用程序的不同类中使用。传统上,每次您需要使用用户对象时,人们都会编写代码来访问数据库并创建对象。相反,您需要一些类似单例的模式。在这种情况下,您的用户对象将被从数据库中查询(和创建)一次,并在请求的整个生命周期内重复使用。如果你在 http 上下文缓存中缓存这个对象(发布它的创建),这是可能的......即HttpContext.Current.Items["foo"]

下面的代码说明了重点……

public class AppUser
{
    public string Username { get; set; }
    public string[] Roles { get; set; }

    public AppUser()
    {
        var appuser = HttpContext.Session["AppUser"] as AppUser;
        if(appuser == null)
            throw new Exception("User session has expired");
        Username = appuser.Username;
        Roles = appuser.Roles;
    }
}


public class WebAppContext
{
    const string ContextKey = "WebAppContext";

    WebAppContext() { } //empty constructor
    public static WebAppContext Current 
    {
        get
        {
            var ctx = HttpContext.Current.Items[ContextKey] as WebAppContext;
            if(ctx == null)
            {
                try
                {
                    ctx = new WebAppContext() { User = new AppUser() };
                }
                catch
                {
                    //Redirect for login
                }
                HttpContext.Current.Items.Add(ContextKey, ctx);                     
            }       
            return ctx;     
        }
    }

    public AppUser User { get; set; }
}

Ps:取自这篇帖子:a request level singleton object in asp.net

【讨论】:

  • @deostoll 您提到的代码是针对每个用户的单个实例。我询问了多个用户访问同一实例的情况
  • @anish 我在一开始就给出了站点范围配置设置的示例场景(与您的 web.config 中的设置完全不同)。例如。这种设置可以用于例如您网站的横幅图片。图像路径可以在应用程序级别变量中设置(在您的情况下是静态变量)
猜你喜欢
  • 2023-03-20
  • 2012-07-15
  • 1970-01-01
  • 1970-01-01
  • 2014-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多