Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Синглтоны и ASP.NET MVC

Автор вопроса: PretzelОтветов: 2

Прямо сейчас у меня возникла проблема с синглтоном, который я только что написал для использования в ASP.NET MVC. Мой синглтон выглядит так:

public sealed class RequestGenerator : IRequestGenerator
{
    // Singleton pattern
    private RequestGenerator()
    {
        requestList = new Stack<Request>();
        appSettings = new WebAppSettings();
    }
    private static volatile RequestGenerator instance = new RequestGenerator();
    private static Stack<Request> requestList = new Stack<Request>();
    // abstraction layer for accessing web.config
    private static IAppSettings appSettings = new WebAppSettings();
    // used for "lock"-ing to prevent race conditions
    private static object syncRoot = new object();
    // public accessor for singleton
    public static IRequestGenerator Instance
    {
        get
        {
            if (instance == null)
            {
                lock (syncRoot)
                {
                    if (instance == null)
                    {
                        instance = new RequestGenerator();
                    }
                }
            }
            return instance;
        }
    }
    private const string REQUESTID = "RequestID";

    // Find functions
    private Request FindRequest(string component, string requestId)
    private List<Request> FindAllRequests(string component, string requestId)

    #region Public Methods required by Interface
    // Gets and increments last Request ID from Web.Config, creates new Request, and returns RequestID
    public string GetID(string component, string userId)

    // Changes state of Request to "submitted"
    public void SetID(string component, string requestId)

    // Changes state of Request to "success" or "failure" and records result for later output
    public void CloseID(string component, string requestId, bool success, string result)

    // Verifies that Component has generated a Request of this ID
    public bool VerifyID(string component, string requestId)

    // Verifies that Component has generated a Request of this ID and is owned by specified UserId
    public bool VerifyID(string component, string userId, string requestId)

    // Returns State of Request ID (Open, Submitted, etc.)
    public Status GetState(string component, string requestId)

    // Returns Result String of Success or Failure.
    public string GetResult(string component, string requestId)
    #endregion
}

И мой код контроллера выглядит так:

public ViewResult SomeAction()
{
    private IRequestGenerator reqGen = RequestGenerator.Instance;
    string requestId = reqGen.GetID(someComponentName, someUserId);
    return View(requestId);
}

Все работает нормально с первого раза, когда я нажимаю на контроллер. "reqGen" назначается экземпляру Singleton. Новый экземпляр запроса добавляется во внутренний список синглтона. И затем мы возвращаем View(). В следующий раз, когда я нажму SomeAction() этого контроллера, я ожидаю, что Singleton будет содержать список с экземпляром SomeClass, который я только что добавил, но вместо этого список пуст.

Что случилось? Сборка мусора поглотила мой объект? Есть ли что-то особенное, что мне нужно учитывать при реализации шаблона Singleton в ASP.NET MVC?

Спасибо!

EDIT: Ааа, лампочка только что загорелась. Таким образом, каждый новый запрос страницы происходит в совершенно новом процессе! Понятно. (мой опыт связан с разработкой настольных приложений, так что для меня это другая парадигма...)

EDIT2: Конечно, вот еще одно уточнение. Моему приложению требовалась система нумерации запросов, где что-то запрашиваемое нуждалось в уникальном идентификаторе, но у меня не было доступной БД. Но он должен был быть доступен каждому пользователю для регистрации состояния каждого запроса. Я также понял, что это может использоваться как способ регулирования сеанса, скажем, если пользователь дважды щелкнул кнопку запроса. Синглтон казался подходящим вариантом, но понимание того, что каждый запрос находится в своем собственном процессе, в основном исключает синглтон. И я предполагаю, что это также устраняет статический класс, верно?

EDIT3: хорошо, я добавил фактический код, с которым я работаю (за вычетом реализации каждого метода, для простоты...) Я надеюсь, что это понятнее.

EDIT4: я награждаю Криса зеленой галочкой, поскольку начинаю понимать, что синглтон на уровне приложения - это то же самое, что наличие Global (а глобальные - это зло, верно?) - All шутки в сторону, лучший вариант на самом деле - иметь БД, и SQLite кажется лучшим вариантом на данный момент, хотя я определенно вижу, что в будущем перейду на экземпляр Oracle. К сожалению, тогда лучшим вариантом было бы использование ORM, но это еще одна кривая обучения. жук.

EDIT5: Последнее редактирование, клянусь. :-)

Поэтому я попытался использовать HttpRuntime.Cache, но был удивлен, обнаружив, что мой кеш постоянно очищается/аннулируется, и я не мог понять, что происходит. Ну, я был сбит с толку побочным эффектом чего-то еще, что я делал: записи в "Web.config"

Ответ --> Без моего ведома, когда "web.config" каким-либо образом изменяется, приложение ПЕРЕЗАПУСКАЕТСЯ! Да, все выбрасывается. Мой синглтон, мой кеш, все. Гах. Неудивительно, что ничего не работало правильно. Похоже, что писать обратно в web.config, как правило, плохая практика, от которой я теперь воздержусь.

Еще раз спасибо всем, кто помог мне в этой беде.

  • Если вы делаете это для кэширования, изучите использование HttpContext.Current.Cache. Todd Smith 16.10.2010
  • Это большой вопрос! Наблюдение за тем, как Pretzel проходит через веревки перехода к веб-разработке, будет полезно для многих будущих программистов. Chris McCall 02.12.2010
  • @ Крис, да, я стараюсь подробно объяснить все в своих вопросах и ответах, чтобы каждый мог извлечь уроки из моих уроков (а также, чтобы, когда я неизбежно забуду какой-то урок через несколько месяцев, я мог быстро напомнить себе о том, что я узнал. .. ;-) Pretzel 02.12.2010

singletongarbage-collection

Ответы

Ответ 1 · рейтинг 3 · NotMe

Синглтон специфичен для экземпляра обработки. Для каждого запроса страницы создается новый экземпляр. Запросы страниц, как правило, считаются не имеющими состояния, поэтому данные из одного не просто сохраняются для другого.

Чтобы заставить это работать на уровне приложения, переменная экземпляра должна быть объявлена ​​там. См. этот вопрос, чтобы узнать, как создать переменную уровня приложения. . Обратите внимание, что это сделает его доступным для всех запросов... что не всегда то, что вам нужно.

Конечно, если вы пытаетесь реализовать какое-либо состояние сеанса, вы можете просто использовать сеанс или какую-либо процедуру кэширования.

ОБНОВЛЕНИЕ
На основе ваших правок: статический класс не должен поддерживать данные. Его цель состоит в том, чтобы просто сгруппировать некоторые общие методы вместе, но он не должен хранить данные между вызовами методов. Синглтон - это совсем другое дело, поскольку это класс, в котором вы хотите, чтобы для запроса был создан только один объект.

Ни то, ни другое не похоже на то, что вы хотите.

Теперь наличие синглтона на уровне приложения будет доступно для всего приложения, но это пересекает запросы и должно быть закодировано соответствующим образом.

Это почти звучит так, как будто вы пытаетесь создать хранилище данных в памяти. Вы можете пойти по пути использования одного из различных механизмов кэширования, например .NET Page .Cache, MemCache или блок приложения кэширования корпоративной библиотеки.

Тем не менее, все они имеют проблему очистки в случае перезапуска рабочего процесса, в котором размещено приложение. Это может произойти в самые неподходящие времена. количество перекомпиляций страниц и т. д.

Вместо этого я настоятельно рекомендую использовать какое-либо постоянное хранилище. Будь то просто xml-файлы, которые вы читаете/записываете, или встраивание чего-то вроде SQL Lite в приложение. SQL Lite - очень легкая база данных, не требующая установки на сервер; вам просто нужны сборки.

Ответ 2 · рейтинг 3 · Mayo

Вы можете использовать Dependency Injection для управления жизнью класса. Вот строка, которую вы могли бы добавить в свой web.config, если бы использовали Castle Windsor.

<component id="MySingleton" service="IMySingleton, MyInterfaceAssembly"
type="MySingleton, MyImplementationAssembly" lifestyle="Singleton" />

Конечно, тема подключения вашего приложения к использованию DI выходит за рамки моего ответа, но либо вы его используете, и этот ответ вам поможет, либо вы можете опробовать концепцию и влюбиться в нее. :)

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы