Слой аннотации данных MVC: где разместить установленный оператор CurrentUICulture?

Я схожу с ума от локализации приложения MVC.

После моего недавнего вопроса я последовал следующему подходу:

  1. Язык хранится в сеансе ["lang"].
  2. Каждый контроллер наследуется от моего собственного BaseController, который переопределяет OnActionExecuting, и в этом методе считывает сеанс и устанавливает CurrentCulture и CurrentUICulture.

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

Объявления полей выглядят так:

[Required(ErrorMessageResourceName = "validazioneRichiesto", ErrorMessageResourceType = typeof(Resources.Resources))]
public string nome { get; set; }

Итак, есть ли какое-нибудь разумное место, куда я могу позвонить?

Я инициализирую связыватель модели аннотации данных в своем конструкторе контроллера.

public CardController() : base() {
    ModelBinders.Binders.DefaultBinder =
    new Microsoft.Web.Mvc.DataAnnotations.DataAnnotationsModelBinder();
}

Итак, поскольку Session всегда имеет значение NULL в конструкторе контроллера, а переопределение действия вызывается ПОСЛЕ того, как аннотация данных проверила поля, где я могу установить CurrentCulture и CurrentUICulture для получения локализованных ошибок?

Я попытался поместить CurrentCulture и CurrentUiCulture в Application_ * (например, Application_AcquireRequestState или Application_PreRequestHandlerExecute), похоже, не имеет никакого эффекта ...


person Palantir    schedule 01.10.2009    source источник


Ответы (4)


Поскольку культура - это глобальная пользовательская настройка, я использую ее в файле global.asax.cs в методе Application_BeginRequest.

Он выполняет свою работу за меня (с использованием файлов cookie), но сеанс также доступен там.

РЕДАКТИРОВАТЬ:

/ Брок Аллен: http://www.velocityreviews.com/forums/t282576-aspnet-20-session-availability-in-globalasax.html/

Сессия доступна в PreRequesthandlerExecute.

Проблема в том, что ваш код выполняется для каждого запроса к серверу, а некоторые запросы (например, для WebResourxe.axd) не используют Session (поскольку обработчик не реализует IRequireSessionState). Поэтому измените свой код, чтобы получить доступ к сеансу только в том случае, если этот запрос имеет к нему доступ.

Измените свой код, чтобы сделать это:

protected void Application_PreRequestHandlerExecute(Object sender, EventArgs e)
{
    if (Context.Handler is IRequiresSessionState || Context.Handler is IReadOnlySessionState)
        SetCulture();    
}

Во всяком случае, не уверен, работает ли он с mvc

person twk    schedule 02.10.2009
comment
Состояние сеанса недоступно в этом контексте. Я тоже пытался поместить его в Application_AcquireRequestState, но это не повлияло на проверку. - person Palantir; 06.10.2009
comment
Хорошо! Вот и все! Большое спасибо. Редактирование исходного вопроса с кодом для использования в будущем. - person Palantir; 07.10.2009


Другой подход, который вы можете использовать, - это указать язык в URL-адресе, что дает следующие преимущества:

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

Для этого используйте метод Application_BeginRequest в Global.asax

Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
    Dim lang As String
    If HttpContext.Current.Request.Path.Contains("/en/") Then
        lang = "en"
    Else
        lang = "es"
    End If
    Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(lang)
    Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(lang)
End Sub

См. этот вопрос для подробнее о том, как это реализовать

person Eduardo Molteni    schedule 02.10.2009
comment
Это выглядит интересно. Вы в настоящее время пользуетесь им? - person twk; 03.10.2009
comment
Да, это фактический производственный код с сайта ASP.net с маршрутизацией. Это не проект MVC, но концепция будет аналогичной. - person Eduardo Molteni; 03.10.2009
comment
Это нормально, но моя проблема все еще существует. Дело не в том, как я передаю информацию о языке, а в том, как передать эту информацию в приложение. - person Palantir; 06.10.2009

OP опубликовал окончательное решение следующим образом, благодаря принятому ответу twk:

void Application_PreRequestHandlerExecute(object sender, EventArgs e) {
  if (Context.Handler is IRequiresSessionState || 
      Context.Handler is IReadOnlySessionState) {
    if (Session["lang"] == null) {
      Session["lang"] = "it";
    }

    if (Request.QueryString["lang"] == "it" || Request.QueryString["lang"] == "en") {
      Session["lang"] = Request.QueryString["lang"];
    }

    string lang1 = Session["lang"].ToString();
    string lang2 = Session["lang"].ToString().ToUpper();

    if (lang2 == "EN")
      lang2 = "GB";

    System.Threading.Thread.CurrentThread.CurrentCulture = 
        System.Globalization.CultureInfo.CreateSpecificCulture(lang1 + "-" + lang2);
    System.Threading.Thread.CurrentThread.CurrentUICulture = 
        System.Globalization.CultureInfo.CreateSpecificCulture(lang1 + "-" + lang2);
  }
}
person Community    schedule 09.02.2015