Прямо сейчас у меня возникла проблема с синглтоном, который я только что написал для использования в 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, как правило, плохая практика, от которой я теперь воздержусь.
Еще раз спасибо всем, кто помог мне в этой беде.