C # Моя первая попытка синглтона, очевидно, не совсем правильная - PullRequest
0 голосов
/ 11 января 2019

На моем сайте есть десятки звонков в базу данных sql, и каждый раз, когда она передает идентификатор пользователя, запрашивающего данные. Я пытаюсь настроить одноэлементный класс, для которого потребуется всего один вызов базы данных, чтобы получить идентификатор человека вместе с другими атрибутами пользователя, которые нужно получить только один раз.

Я думал, что у меня все настроено правильно, и, похоже, оно работает, поэтому я перенес изменение кода в рабочий режим и получил звонки от нескольких пользователей, которые говорили, что при входе в систему все они идентифицируются как я. Это основано на приветственном сообщении в верхней части моей домашней страницы с надписью «Добро пожаловать», и все userName отображаются как я.

Мой синглтон ниже. После получения вызова я начал отладку и обнаружил, что метод formValues ​​(), в котором, как я думал, устанавливаются значения, никогда не вызывается. Единственная вещь, которая вызывается - это открытый метод Instance. Я предполагаю, что это очевидно для всех, кто знает, что они делают:).

Я не думаю, что это уместно, но экземпляр переменных вызывается в моем коде, например: 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;
        }
    }
}

Ответы [ 3 ]

0 голосов
/ 11 января 2019

Проблема в том, что эти свойства (поля, на самом деле) находятся в синглтоне:

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()

... который создаст экземпляр UserData и вернет его.


Для чего бы это ни стоило, для большинства сценариев нам не нужно создавать синглтон.

Предположим, у вас есть этот класс:

public class SqlUserDataProvider
{
    UserData GetUserData()
    {
     ...
    }
}

Если конструктор не делает ничего «тяжелого», например, чтения данных или файлов, вы можете просто создавать новый экземпляр каждый раз, когда он вам нужен. Это менее эффективно, чем использование одного экземпляра, но разница обычно настолько незначительна, что не стоит об этом думать.

Или вы можете создать один экземпляр и использовать его повторно. В этом случае вы используете его как синглтон, но технически это не так. Синглтон - это класс, написанный так, что можно создать только один его экземпляр. В большинстве случаев просто нет причин делать это. Это дополнительные строки кода, чтобы строго наложить ограничения на то, как мы используем класс. Это может потенциально сделать код менее обслуживаемым и сложным для отладки. Так что это лишняя работа, ни для выгоды, ни для негативной выгоды.

0 голосов
/ 11 января 2019

Объект экземпляра создается только один раз за время существования приложения. Таким образом, ваш приватный конструктор formValues ​​(), в котором вы получаете FormsIdentity, фактически выполняется только один раз после первого запуска приложения.

После этого для всех входящих запросов выдается уже заполненный экземпляр. Вот почему вы видите то же имя пользователя для дальнейших запросов.

Поскольку требование является индивидуальным для каждого пользователя, а не глобальным для всего приложения, «синглтон», вероятно, не поможет. Спасибо.

0 голосов
/ 11 января 2019

По сути, вы хотите сделать кеш. Для http-запросов вам нужно проверить, есть ли значение в кеше, если нет - читать из базы данных, в противном случае использовать кеш. Вы можете начать со встроенного кэша

Что касается синглетонов, самое простое решение - реализовать их с помощью Lazy. Вот хорошая статья

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...