C# 我的第一次单身尝试显然不太正确

C# 我的第一次单身尝试显然不太正确,c#,singleton,C#,Singleton,在我的网站上,有几十个对sql数据库的调用,每次调用都会传递请求数据的用户的ID。我正在尝试设置一个singleton类,该类只需对数据库进行一次调用,即可获取个人ID以及其他只需获取一次的用户属性 我认为我已经把所有的东西都设置好了,而且似乎都能正常工作,所以我把代码更改转移到了生产环境中,并且收到了一些用户的电话,他们说当他们登录时,他们都被识别为我。这是基于我主页顶部的欢迎信息,上面写着欢迎,每个人的用户名都显示为我 我的单身汉在下面。在得到调用后,我开始调试,我发现我认为正在设置值的fo

在我的网站上,有几十个对sql数据库的调用,每次调用都会传递请求数据的用户的ID。我正在尝试设置一个singleton类,该类只需对数据库进行一次调用,即可获取个人ID以及其他只需获取一次的用户属性

我认为我已经把所有的东西都设置好了,而且似乎都能正常工作,所以我把代码更改转移到了生产环境中,并且收到了一些用户的电话,他们说当他们登录时,他们都被识别为我。这是基于我主页顶部的欢迎信息,上面写着欢迎,每个人的用户名都显示为我

我的单身汉在下面。在得到调用后,我开始调试,我发现我认为正在设置值的formValues方法从未被调用。唯一被调用的是公共实例方法。我猜这对每个知道自己在做什么的人来说都是显而易见的

我认为这与此无关,但在我的代码中调用了变量的实例,如:formValues.instance.firstName

那么我离这里有多近?这东西可以抢救吗

public sealed class formValues : System.Web.Services.WebService
{
    static readonly formValues instance = new formValues();

    public string userName;
    public string firstName;
    public string personID;
    public string secBlur;
    public int admin;
    public int fafsa;
    public int staff;

    static formValues()
    {

    }

    formValues()
    {
        //This retrieves the person logged into windows/active directory
        FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
        userName = id.Name;

        // Grab this user's firstname, personID, and Admin status
        string mySQL = "exec get_userData @userName";
        string cf = System.Configuration.ConfigurationManager.ConnectionStrings["DistrictAssessmentDWConnectionString"].ConnectionString;

        SqlConnection connection = new SqlConnection(cf);
        SqlCommand command = new SqlCommand(mySQL, connection);

        command.Parameters.AddWithValue("@userName", userName);

        connection.Open();

        SqlDataReader dr = command.ExecuteReader();

        if (dr.HasRows)
        {
            while (dr.Read())
            {
                personID = dr["personID"].ToString();
                firstName = dr["firstName"].ToString();
                admin = Convert.ToInt32(dr["admin"]);
                secBlur = dr["secBlur"].ToString();
                fafsa = Convert.ToInt32(dr["FAFSA"]);
                staff = Convert.ToInt32(dr["staffSec"]);
            }
        }

        connection.Close();
    }

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

基本上,你想要做一个缓存。对于http请求,您需要检查值是否已在缓存中,如果未从数据库中读取,则使用缓存。 您可以从内置的


对于单例,最简单的解决方案是使用Lazy实现它们。问题是这些属性字段实际上是在一个单例中:

public string userName;
public string firstName;
public string personID;
public string secBlur;
public int admin;
public int fafsa;
public int staff;
…以及它们在构造函数中填充的事实。这意味着第一次创建类时,它会被填充。如果将同一个类实例作为单例重复使用,则构造函数将永远不会再次被调用,这意味着填充的值将被设置一次并永远保持不变

换句话说,您的用户数据是单例数据。除非你只有一个用户,否则这是不好的

首先,我将从包含数据的类中分离检索数据的类

数据可能如下所示:

public class UserData
{
    public string UserName { get; set; }
    public string FirstName { get; set; }
    // ..etc...
}
public UserData GetUserData()
该模型包含数据。它不包含填充数据的代码

然后,创建一个检索数据的类。它不应该检索构造函数中的数据。构造函数用于创建类。我们不会把课堂上实际做的东西放在那里

该类可能有如下方法:

public class UserData
{
    public string UserName { get; set; }
    public string FirstName { get; set; }
    // ..etc...
}
public UserData GetUserData()
…这将创建UserData的实例并返回它

无论如何,对于大多数场景,我们不需要创建单例

假设您有这个类:

public class SqlUserDataProvider
{
    UserData GetUserData()
    {
     ...
    }
}
如果构造函数不执行任何繁重的操作,比如读取数据或文件,那么您可以在每次需要时创建一个新实例。与使用单个实例相比,它的效率较低,但差异通常非常微小,因此不值得考虑


或者,您可以创建一个实例并重新使用它。在这种情况下,您将其作为一个单例使用,但从技术上讲,它不是一个单例。单例是类编写的,因此只能创建它的单个实例。大多数时候,没有理由这么做。这是额外的代码行,用于严格限制我们如何使用该类。它可能会降低代码的可维护性和调试难度。因此,无论是没有好处还是负面好处,这都是额外的工作。

实例对象在应用程序生命周期中只创建一次。 所以,您的私有构造函数formValues,即您获取FormsIdentity的地方,实际上在应用程序首次启动后执行一次

之后,对于所有传入的请求,将给出已填充的实例。 这就是为什么对于任何进一步的请求,您都会看到相同的用户名


因为需求是基于每个用户的,而不是跨应用程序的全局性需求,所以singleton可能不会有帮助。谢谢。

由于该字段是静态的,所以在第一次构造单例时,无法使用garauntee。在构建时不太可能拥有所需的HttpContext,也不会为每个用户构建它。Singleton似乎是解决您试图解决的问题的错误方法。感谢@Jonathon Chase,我愿意接受建议…您是否有更好方法的建议?您可以通过删除实例字段和属性进行调整,并添加一个名为Create的工厂方法来调用构造函数。这将允许您按需创建和填充对象。使用@JonSkeet的懒惰单例模式:我昨天尝试使用缓存,它随机获取登录网站的用户ID-每次我点击刷新,它都会欢迎我作为另一个人:。很明显,我在核心做的一些事情似乎是正确的@乔纳森·蔡斯说了一些让我感到奇怪的话——我想是HTTPW
你可以从调用计算机中获取经过身份验证的人的姓名…我需要给自己上一堂关于http命令如何工作的复习课吗?因为你已经尝试创建了一个单例,并且提到了缓存,听起来您想要的是为每个web请求调用一次,然后避免在同一个请求中反复调用它。准确吗?如果是这样,有办法做到这一点。我没有讨论这个问题,因为这不是问题的核心。这是一个Web服务吗,就像.asmx文件一样?