Подтвердить что ты не робот

Ресурсы ресурсов ASP.Net MVC иногда неправильно загружаются программой ResouceManager

Обзор

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

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

Это продолжается до тех пор, пока приложение не будет перезапущено.

Деталь

Производственная среда - IIS 8 в Windows Server 2012. Приложение реализовано в ASP.Net MVC 4.

Приложение решает, какой язык он обслуживает входящим URL. Так www.mysite.com будет британский английский www.mysite.fr будет французский и т.д.

У нас есть реализация IHttpModule, которая зарегистрирована через Web.config. В методе Init модуля он прикрепляет обработчик к событию BeginRequest. В этом методе проверяется входящий URL-адрес, а в потоке CurrentUICulture задано соответствующее значение. en-GB для www.mysite.com, fr-FR для www.mysite.fr и т.д.

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

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

Анализ

Мы смогли воспроизвести это локально на компьютере разработки, бросив запросы в приложение во время запуска (используя Fiddler). Сайт показывал немецкий контент для некоторых файлов ресурсов на британской версии сайта.

Проверяя очевидных преступников в нашем коде (что CurrentUICulture правильно настроен модулем HTTP и остается верным во время обработки запроса), мы начали смотреть на менеджера ресурсов.

При запуске приложения в этом неправильном состоянии мы рассмотрели содержимое свойства _resourceSets в классе ResourceManager. Это словарь, основанный на коде культуры ISO. Изучив содержимое en-GB, мы обнаружили, что он действительно содержал строки ресурсов из немецкой версии файла ресурсов.

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

Кто-нибудь еще испытал такое поведение и кто-нибудь знает об обходных решениях?

Спасибо.

4b9b3361

Ответ 1

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

У меня есть несколько советов, которые вы можете начать с:

  • Убедитесь, что ваш обработчик НЕ используется повторно. Я предполагаю, что вы внедрили IHttpHandler, возвращаете false для свойства IsReusable, так как несколько потоков должны ударить его одновременно, и новый экземпляр будет создан для каждого запроса.
  • Не используйте обработчик... Обработчик не является идеальным решением для чего-то подобного. Предпочтительное место для установки культуры потока находится в Application_AcquireRequestState, которые будут правильно запущены для каждого запроса без перекрытия.
  • Вместо этого используйте обработчик маршрутизации: http://adamyan.blogspot.com/2010/07/addition-to-aspnet-mvc-localization.html

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

Ответ 2

Недавно мы столкнулись с той же проблемой. Это выглядит как условие гонки в ResourceManager (или его вспомогательном коде). Я собрал репрограмму в https://bitbucket.org/onyxmaster/resmanrc. Кроме того, я зарегистрировал ошибку на сайте MS Connect, https://connect.microsoft.com/VisualStudio/feedback/details/806505/.

P.S. Я не уверен, что это считается ответом, так как не существует обходного пути, о котором я знаю, но по крайней мере сейчас есть отчет об ошибке и ошибке.

Ответ 3

Используете ли вы действия async MVC? Если да, когда вы ожидаете вызов (с ConfigureAwait установлено значение false), поток обработки повторно используется во время его выполнения. "возвращающий" поток (поток, выполняющий код после ожидаемого вызова) не является тем же и может потерять все ранее заданные свойства. ConfigureAwait должен быть установлен на false, чтобы предотвратить взаимоблокировки, поэтому немедленного решения нет.

Еще одна вещь, которую нужно проверить, - это кеширование, если вы используете attrbute [Cache] или кешируете менеджера resouce.

Ответ 4

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

Ответ 5

Я прочитал этот ответ из других ресурсов. И хотелось бы обернуть ResourceManager следующим образом, чтобы новый RexourceManager() не участвовал в загруженном многопоточном вызове:

public sealed class LocalizationHandler
{
   [ThreadStatic]
   private static ResourceManager _manager
   private readonly ConcurrentBag<ResourceManager> 
       _localizationIdentityCollection = new ConcurrentBag<ResourceManager>();

   private LocalizationHandler(){}

   public static LocalizationHandler Load(ResourceType source)
   {
      switch (source)
      {
          case typeA:
              //check if resource exist in the concurrent bag or create a new one
           _manager = getManager();
           break;
      }
      return this;
   }

   public string Get(string key)
   {
       return _manager.Get(key)
   }
}

Затем вы можете вызвать:

LocalizationHandler.Load(ResourceType.TypeA).Get("your resource Key String")

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