Использование HttpContext.Current.Application для хранения простых данных - PullRequest
10 голосов
/ 21 июня 2010

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

Я думаю об использовании 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"].

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

Ответы [ 5 ]

31 голосов
/ 21 июня 2010

То, что вы на самом деле делаете, это Кэширование , и это здорово, поскольку вы уменьшаете количество обращений к внешнему хранилищу (базе данных или файлу, что угодно). Компромисс - использование памяти, конечно. Теперь практически любая современная веб-инфраструктура, включая 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;

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

НТН!

8 голосов
/ 21 июня 2010

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

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

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

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

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

    статический MyObject myObject = LoadFromSql ();

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

3 голосов
/ 01 марта 2017

Да, использование 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). Поэтому сводите данные в статических типах к минимуму.)

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

3 голосов
/ 21 июня 2010

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

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

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

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

0 голосов
/ 21 июня 2010

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

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

...