2010-06-21 3 views
9

Я хочу сохранить небольшой список простого объекта (содержащего три строки) в моем приложении ASP.NET MVC. Список загружается из базы данных и редко обновляется путем редактирования некоторых значений в области администрирования сайта.Использование HttpContext.Current.Application для хранения простых данных

Я думаю об использовании HttpContext.Current.Application для его сохранения. Таким образом, я могу загрузить его в Global.asax:

protected void Application_Start() 
    { 
     RegisterRoutes(RouteTable.Routes); 

     HttpContext.Current.Application["myObject"] = loadDataFromSql(); // returns my object 
    } 

И тогда можно легко ссылаться на него каких-либо контроллеров или представлений по мере необходимости. Затем в случае, когда область администрирования вызывает действие контроллера updateMyObject, я могу просто обновить БД и снова загрузить его и заменить HttpContext.Current.Application["myObject"].

Есть ли какие-либо недостатки в этом? Похоже, что он будет отлично работать для того, чего я пытаюсь достичь, однако кто-нибудь знает, как лучше это сделать, если предположить, что есть какой-то главный недостаток метода, который я изложил?

+1

Что происходит, когда список обновляется? Собираетесь ли вы каждый раз перезагружать приложение? –

ответ

27

Что вы на самом деле делаете, это Кэширование, и это здорово, поскольку вы уменьшаете вызовы во внешнее хранилище (базу данных или файл, что угодно). Конечно, компромисс - использование памяти. Теперь почти любая современная веб-инфраструктура, включая ASP.NET, включает в себя какой-то механизм кэширования. Либо вы его используете, либо используете какую-то глобальную переменную.

Сохранение данных в встроенном объекте ASP.NET Cache имеет ряд существенных преимуществ, поскольку этот механизм фактически проверяет использование памяти и удаляет кэшированные данные в соответствии с некоторыми правилами.

Однако, если данные, которые вы хотите кэшировать, интенсивно используются в приложении, а его размер не слишком велик (скажем, меньше 1 МБ), вы можете захотеть сохранить его в качестве глобальной переменной.

В ASP.NET глобальные переменные достигаются путем использования объекта Application, как описано в вашем вопросе, или путем записи публичных статических свойств/полей во внутреннем/открытом классе.

Вот мое решение для статических свойств. Обратите внимание, что я использую объект блокировки, чтобы защитить внутренние данные от повреждения. Это выглядит следующим образом:

public class WhateverClass 
{ 
    private static object theLocker = new object(); 
    private static YourDataType theData; 
    public static YourDataType TheData 
    { 
    get 
    { 
     lock (theLocker) 
     { 
     return theData; 
     } 
    } 
    set 
    { 
     lock (theLocker) 
     { 
     theData = value; 
     } 
    } 
    } 
} 

Использование очень просто:

Первый раз, в Application_Start:

protected void Application_Start() 
{ 
    RegisterRoutes(RouteTable.Routes); 

    WhateverClass.TheData = loadDataFromSql(); 
} 

В любом контроллере:

var myData = WhateverClass.TheData; 

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

HTH!

+0

Спасибо, это то, что я искал. – macca1

+0

Действительно спасибо !, это полезно для меня. Но в моем случае (ASP.NET API) я должен хранить более крупные данные в памяти (1 ГБ с этого времени (и подсчет), что составляет более 10 000 записей - для хранения в списке/словаре. Должен ли я идти с вашим подходом – hungdoan

+1

@hungdoan, я бы использовал такое решение, как MemCache - внешняя служба кеширования. Не думаю, что хранить кеширование в приложении ASP.NET более 1 ГБ - хорошая идея. –

0

Application_Start действительно запускается только в App Pool Recylce, IIS Сбрасывает или перезагружает. Если вы часто обновляете эти значения, почему бы не сохранить их в своем web.config и не получить к ним доступ?

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

3

Если вы используете один веб-сервер, этот подход будет работать. Рассмотрим объект Cache для этого, поскольку он предоставляет больше возможностей для истечения срока действия, если вам нужна такая функциональность. (См. Сравнение, хотя и в возрасте одного года, here.)

Если вы когда-либо собираетесь развертывать ферму веб-сервера или ее эквивалент, вы должны использовать memcached или другой механизм кэширования веб-фермы. Оба объекта Application и Cache обычно существуют только в одном сервере; если ваш пользователь может поражать несколько веб-серверов во время сеанса (а кеш должен быть идентичным), вам понадобится общий кэш, который можно увидеть на каждом из потенциальных веб-серверов.

Независимо от того, какой путь вы предпримете, вам потребуется аннулировать/перезагружать кеш при изменении базовых данных, который является настраиваемым кодом, который зависит от приложения.

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

+0

Спасибо за проницательный ответ. Я только развертываю на одном сервере, но это интересно отметить для фермы веб-серверов. – macca1

6

HttpContext.Current.Application, по существу, похмелье, который необходим для обеспечения обратной совместимости с классическим ASP. Это по существу статическая Hashtable с классической семантикой блокировки ASP (Application.Lock/Application.UnLock).

В слабо типизированных Hashtable, вам нужно будет отбрасывать объекты извлекаются:

MyObject myObject = (MyObject) HttpContext.Current.Application["myObject"]; 

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

  • статическое поле, используя .NET запирающий семантику, если вам нужно блокировки (например, C# блокировки ключевого слова, или ReaderWriterLockSlim экземпляр, в зависимости от ваших требований):

    static MyObject myObject = LoadFromSql();

  • ASP.NET Cache - который имеет широкие функциональные возможности для управления истечения срока действия, зависимости, ...

2

Да, с помощью HttpContext.Current.Application будет прекрасно работать для того, что вы делаете. Нет проблем.

«HttpContext.Current.Application» - это просто ссылка на статический глобальный объект HttpApplicationState в .NET для вашего веб-приложения, из которого должен быть один глобальный экземпляр для каждого веб-приложения. Сохраняя данные там, вы обеспечиваете быстрый, потокобезопасный доступ к вашим глобальным переменным. Убедитесь, что их блокировки при обновлении значения, как в этом примере:

System.Web.HttpContext.Current.Application.Lock(); 
System.Web.HttpContext.Current.Application["WebApplicationPath"] = MyWebApplicationPath; 
System.Web.HttpContext.Current.Application.UnLock(); 

Как уже упоминалось, вы также можете создать ряд статических классов в вашем App_Code или другую папку и там хранить глобальные статические значения, а также ваши значения HttpContext.Current.Application, где их можно безопасно проверять на значения или обновлять из базы данных или обновлять и проверять друг друга, работая в тандеме. Обычно я создаю статический глобальный класс, чтобы помочь в управлении и поиске хранимых переменных приложения. Таким образом, у вас есть как государственный словарь класса HttpApplicationState, так и статические объекты веб-приложения, работающие вместе для обмена и поддержания глобальных значений.(Имейте в виду, что каждый статический класс назначается для каждого рабочего процесса, и по умолчанию на многих веб-серверах II/веб-приложений по умолчанию может быть до 10 WP, поэтому сохраняйте данные в статических типах как минимум.)

Keep поскольку некоторые упомянутые серверные фермы не используют состояние приложения. Есть много способов справиться с этим. Я не поклонник кеша из-за того, как он может истекать, терпеть неудачу, устаревать или искажаться. Более простым решением является простое использование запросов базы данных и URL-адресов для связи между серверами и поддержания состояния. Удачи!

+0

Ограничение максимального размера для данных, которые вы помещаете в запись для 'System.Web.HttpContext.Current.Application'. Например, запись с 50 МБ? – Heinrich