Шаблон Singleton в веб-приложениях

Я использую одноэлементный шаблон для datacontext в своем веб-приложении, поэтому мне не нужно его создавать каждый раз, однако я не уверен, как работают веб-приложения, открывает ли IIS поток для каждого подключенного пользователя? если да, то что произойдет, если мой синглтон не будет потокобезопасным? Кроме того, можно ли использовать шаблон singleton для datacontext? Спасибо.

Ответ 2

Я использую шаблон singleton для datacontext в своем веб-приложении

"Синглтон" может означать много разных вещей в этом контексте. Это один экземпляр для запроса? За сеанс? В потоке? Per AppDomain (экземпляр static)? Последствия всех этих факторов сильно различаются.

"Singleton" для каждого запроса (хранится в HttpContext) в порядке. Один сингл на сеанс не рекомендуется, но его можно заставить работать. Один синглтон для потока может работать, но может привести к неожиданному и трудно отлаживаемому поведению. Синглтон для приложения или AppDomain - это катастрофа, ожидающая своего появления.

так что я не должен создавать его каждый раз

Создание DataContext очень, очень дешево. Метаданные хранятся в глобальном масштабе, а соединения не создаются до тех пор, пока вы фактически не выполните запрос. Нет причин пытаться оптимизировать построение экземпляра DataContext.

однако я не уверен, как работают веб-приложения, открывает ли IIS поток для каждого подключенного пользователя?

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

если да, то что произойдет, если мой синглтон не будет потокобезопасным?

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

Также, хорошо ли использовать шаблон singleton для datacontext? Спасибо.

A DataContext не является потокобезопасным, и в этом случае, даже если вы заблокируете DataContext, пока он используется (это уже плохая идея), вы все равно можете столкнуться с кросс-потоком/крестом -просить условия гонки. Не делайте этого.

DataContext экземпляры должны ограничиваться областью действия одного метода, когда это возможно, используя предложение using. Следующее лучшее - сохранить их в HttpContext. Если вам нужно, вы можете сохранить его в сеансе, но есть много вещей, о которых вам нужно знать (см. этот вопрос. Я недавно ответил на ObjectContext - почти все те же принципы применяются к DataContext).

Но, прежде всего, не создавать "глобальные" одноэлементные экземпляры DataContext в приложении ASP.NET. Вы будете глубоко сожалеть об этом позже.

Ответ 3

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

Итак, если у вас есть какая-то информация о состоянии в веб-приложении, которая не должна быть видимой другим пользователям, она не должна быть абсолютно не статичной. Храните эту информацию в сеансе пользователя или конвертируйте статический var в следующее:

public static Data SomeData
{
    get
    {
        if (HttpContext.Session["SomeData"] == null)
            HttpContext.Session["SomeData"] = new Data();
        return (Data)HttpContext.Session["SomeData"];
    }
}

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

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

Ответ 4

@ryudice веб-сервер создает новый поток для каждого запроса. Я думаю, что лучший подход заключается в том, чтобы привязать к каждому запросу datacontext, что означает, что каждый раз, когда вы выполняете запрос, вы должны создавать новый datacontext. Хорошим способом достижения этого является использование инструмента DI, например StructureMap. Эти инструменты позволяют настраивать жизненный цикл экземпляров, которые вы настраиваете, например, в вашем случае вы должны настроить класс XDataContext для охвата HttpContext.

С уважением.