2016-07-08 8 views
1

У меня есть веб-приложение ASP.NET MVC 5, работающее под веб-сайтом в IIS 8, где мне нужно программно менять язык во время выполнения пользователем предпочтение от того, что я прочитал из БД и сохранил в переменной сеанса, и это значение может измениться во время выполнения с выпадающим списком.Ресурсы локализации ASP.NET MVC 5 замораживаются и не меняют язык, несмотря на изменение CurrentThread.CurrentCulture

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

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

Это блок бритвы я использую для проверки CurrentCulture

<div style="display:none; visibility: hidden;">Thread 
@System.Threading.Thread.CurrentThread.CurrentCulture</div> 

И во время выполнения, когда язык или Resx являются заморожен/stucked на уровне приложений значение действительно правильный и выбран, но это не соответствует язык, отображаемый в представлениях, и обычно не работает нормально, пока я не сделаю, например, изменение в файле web.config или перезапустил приложение, а затем он отлично работает некоторое время, но не длится слишком много времени.

<div style="display:none; visibility: hidden;">Thread en-US</div> 

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

Я попытался разместить изменение логики культуры в представлениях бритвы, фильтрах действий и базовом контроллере, но это не решило проблему, ранее у меня был базовый контроллер, который весь мой контроллер унаследовал, и логика в Global.asax .cs изменить и определить культуру.

Мой текущий подход состоял в том, чтобы удалить базовый контроллер и использовать как в Global.asax.cs Application_AcquireRequestState (я тоже пытался использовать Application_BeginRequest, но как-то слишком рано в жизненном цикле) и Action Filter.

Это в Global.asax.cs

protected void Application_AcquireRequestState(object sender, EventArgs e) 
    { 
     if (Context.Session != null && Context.Session["CultureName"] != null) 
     { 
      string cultureName = Context.Session["CultureName"].ToString(); 

      CultureInfo cultureInfo = new System.Globalization.CultureInfo(cultureName); 

      Thread.CurrentThread.CurrentCulture = cultureInfo; 
      Thread.CurrentThread.CurrentUICulture = cultureInfo; 

     } 
    } 

И мой фильтр действий, как этот

public class CultureActionAttribute : IAuthorizationFilter 
{ 
    public void OnAuthorization(AuthorizationContext filterContext) 
    { 
     string cultureName = null; 

     string tenant = filterContext.RouteData.Values["Tenant"] as string; 
     if (!String.IsNullOrWhiteSpace(tenant)) 
     { 
      TenantService tenantService = new TenantService(tenant); 

      cultureName = CultureHelper.GetImplementedCulture(tenantService.Tenant.LanguageCulture); 

      tenantService.Unit.Dispose(); 

     } 
     //Logic to override cultureName value by getting the user preference language 

     CultureInfo cultureInfo = new System.Globalization.CultureInfo(cultureName); 

     Thread.CurrentThread.CurrentCulture = cultureInfo; 
     Thread.CurrentThread.CurrentUICulture = cultureInfo; 
    } 
} 

И я добавил его в FilterConfig

public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
    { 
     filters.Add(new HandleErrorAttribute()); 
     filters.Add(new CultureActionAttribute()); 
     // 
    } 

Я даже пытался использовать ClearCachedData, когда пользователь меняет культуру.

Thread.CurrentThread.CurrentCulture.ClearCachedData(); 

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

Я не использую ни одного тега глобализации в web.config.

Значение, которое отслеживается в представлениях CurrentThread.CurrentCulture всегда правильно, что неправильно, это замораживание с использованием ресурсов.

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

Ресурсы

enter image description here

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

ответ

0

Я верю, что здесь происходит то, что вы настраиваете культуру в другой теме, чем там, где вы на самом деле ее используете. Вы устанавливаете культуру в асинхронном методе BeginExecuteCore, который может не последовательно передавать культуру в рабочий поток пользовательского интерфейса вашего приложения. Это объясняет прерывистое поведение - вы, вероятно, видите, что оно «замерзает» во время большой нагрузки, когда потоки приложений работают медленно.

Never use a base controller in MVC - это никогда не будет хорошей идеей. Вместо этого для сквозных задач, таких как локализация, вы можете использовать global filter. Это не только помогает вам решить проблему с асинхронным доступом, но и способствует более слабому дизайну. Ниже приведен пример фильтра, который получает культуру от текущего маршрута:

using System.Globalization; 
using System.Threading; 
using System.Web.Mvc; 

public class CultureFilter : IAuthorizationFilter 
{ 
    private readonly string defaultCulture; 

    public CultureFilter(string defaultCulture) 
    { 
     this.defaultCulture = defaultCulture; 
    } 

    public void OnAuthorization(AuthorizationContext filterContext) 
    { 
     var values = filterContext.RouteData.Values; 

     string culture = (string)values["culture"] ?? this.defaultCulture; 

     CultureInfo ci = new CultureInfo(culture); 

     Thread.CurrentThread.CurrentCulture = ci; 
     Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(ci.Name); 
    } 
} 

Использования

public class FilterConfig 
{ 
    public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
    { 
     filters.Add(new CultureFilter(defaultCulture: "nl")); 
     filters.Add(new HandleErrorAttribute()); 
    } 
} 

Я хотел бы также утверждать, что using session state for localization is not a great idea - в конце концов, вы оставили в черной дыре, когда сессия истекает.

Местные жители не являются персонализация. Местные жители: содержание. Правильный способ подачи уникального контента - - это уникальный URL-адрес. Если вы это сделаете, выбор культуры будет таким же простым, как выбор нового URL-адреса, и он автоматически «застрянет», потому что MVC повторно использует значения маршрута. Он никогда не истечет, даже если пользователь отправит URL-адрес кому-то другому. И самое главное, вся работа, которую вы сделали, переводя ваш сайт на несколько языков, будет , видимая поисковыми системами, поэтому у нее будет гораздо больший выигрыш.

См. ASP.NET MVC 5 culture in route and url для рабочего примера подхода на основе URL.

+0

Я полностью согласен с вами относительно получения языка с URL-адреса с точки зрения SEO, но это частное приложение, которое вообще не требует SEO. Я действительно делаю это, потому что мой маршрут карты работает примерно так: «{tenant}/{controller}/{action}/{id}" каждый арендатор - это база данных, которая имеет предпочтение по умолчанию для языка, которое я прочитал из запроса БД и у меня есть вся эта логика в CultureHelper, но у каждого арендатора есть разные пользователи с разными языковыми предпочтениями, которые могут отменить предпочтение их арендатора. –

+0

И раньше я использовал свой путь с помощью фильтров, как вы предлагаете, и я все еще держусь замерзая, но если я использую только это, не все правильно правильно локализовано, даже если оно не зависает. Мне нужно также использовать Application_AcquireRequestState в Global.asax, cs. То, что я не делал, это удалить логику BaseController при одновременном использовании фильтра (что могло бы сделать вашу теорию правильной), тогда я попробовал только с базовым контроллером, теперь я просто оставил только фильтр Action и AcquireRequestState вместе. –

+0

И, как я сказал в сообщении, выбор и чтение языка всегда хорошо срабатывали, потому что я читал правильное значение в скрытом тексте взглядов. Большое спасибо за помощь. Но посмотрим, работает ли это. И тогда я могу поддерживать только один подход - либо фильтр действия, либо логику global.asax. –

0

Единственный способ, которым я мог бы обеспечить, чтобы получить правильные ресурсы было сделать работу вокруг переопределять непосредственно над ресурсами свойство CurrentThreadUICulture для всех поисков ресурсов в конце моего CultureFilter

Resources.Resource.Culture = cultureInfo; 

И это сделало трюк !, получая преимущество, чтобы иметь только отдельные файлы в качестве глобальных ресурсов, поэтому теперь все работает так, как ожидалось, но я понимаю, что это будет неудобно для нескольких файлов ресурсов и пространств имен.Тем не менее, для меня не было другого способа, в котором я мог бы гарантировать, что смена языка будет работать и не замерзнет после попытки использования базового контроллера и атрибута actionfilter Iauthorization или использования Application_AcquireRequestState в Global.asax.cs, где ни один из трех методов всегда мог правильно изменить язык пользовательского интерфейса из-за замораживания, несмотря на то, что Thread.CurrentThread.CurrentUICulture всегда правильно менялся с помощью трех подходов.