Лучшее место для установки CurrentCulture для многоязычных веб-приложений ASP.NET MVC - PullRequest
41 голосов
/ 22 ноября 2011

Для многоязычного веб-приложения ASP.NET MVC 3 я определяю Thread.CurrentThread.CurrentCulture и Thread.CurrentThread.CurrentUICulture на заводе контроллера следующим образом:

public class MyControllerFactory : DefaultControllerFactory {

    protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType) {

        //Get the {language} parameter in the RouteData
        string UILanguage;
        if (requestContext.RouteData.Values["language"] == null)
            UILanguage = "tr";
        else
            UILanguage = requestContext.RouteData.Values["language"].ToString();

        //Get the culture info of the language code
        CultureInfo culture = CultureInfo.CreateSpecificCulture(UILanguage);
        Thread.CurrentThread.CurrentCulture = culture;
        Thread.CurrentThread.CurrentUICulture = culture;

        return base.GetControllerInstance(requestContext, controllerType);
    }

}

Код вышепочти год сейчас!Итак, я открываю для предложений.

И я регистрирую это в файле Global.asax как:

ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());

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

Я не вникнул в главную роль ControllerFactory и не могу сравнить ее с ActionFilterAttribute.

Что вы думаете о лучшем месте для этого типадействие

Ответы [ 5 ]

56 голосов
/ 16 июня 2012

Я использовал глобальный ActionFilter для этого, но недавно я понял, что установка текущей культуры в методе OnActionExecuting в некоторых случаях слишком поздняя. Например, когда модель после запроса POST поступает в контроллер, ASP.NET MVC создает метаданные для модели. Это происходит до того, как какие-либо действия будут выполнены В результате значения атрибутов DisplayName и другие аннотации данных обрабатываются с использованием культуры по умолчанию на этом этапе.

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

CultureAwareControllerActivator.cs :

public class CultureAwareControllerActivator: IControllerActivator
{
    public IController Create(RequestContext requestContext, Type controllerType)
    {
        //Get the {language} parameter in the RouteData
        string language = requestContext.RouteData.Values["language"] == null ?
            "tr" : requestContext.RouteData.Values["language"].ToString();

        //Get the culture info of the language code
        CultureInfo culture = CultureInfo.GetCultureInfo(language);
        Thread.CurrentThread.CurrentCulture = culture;
        Thread.CurrentThread.CurrentUICulture = culture;

        return DependencyResolver.Current.GetService(controllerType) as IController;
    }
}

Global.asax.cs

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        ...
        ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactory(new CultureAwareControllerActivator()));
    }
}
7 голосов
/ 20 ноября 2014

Я знаю, что anser уже был выбран. Опция, которую мы использовали, состояла в том, чтобы просто инициализировать текущую культуру потока в событии OnBeginRequest для приложения. Это обеспечивает обнаружение культуры при каждом запросе

public void OnBeginRequest(object sender, EventArgs e)
{
   var culture = YourMethodForDiscoveringCulutreUsingCookie();
   System.Threading.Thread.CurrentThread.CurrentCulture = culture;
   System.Threading.Thread.CurrentThread.CurrentUICulture = culture;
}
4 голосов
/ 22 ноября 2011

Альтернативное место для этого - поместить этот код в метод OnActionExecuting настраиваемого ActionFilter, который можно зарегистрировать в коллекции GlobalFilters:

http://weblogs.asp.net/gunnarpeipman/archive/2010/08/15/asp-net-mvc-3-global-action-filters.aspx

3 голосов
/ 06 августа 2013

Вместо переопределения OnActionExecuting вы можете переопределить Initialize здесь, как это

protected override void Initialize(RequestContext requestContext)
{
        string culture = null;
        var request = requestContext.HttpContext.Request;
        string cultureName = null;

        // Attempt to read the culture cookie from Request
        HttpCookie cultureCookie = request.Cookies["_culture"];
        if (cultureCookie != null)
            cultureName = cultureCookie.Value;
        else
            cultureName = request.UserLanguages[0]; // obtain it from HTTP header AcceptLanguages

        // Validate culture name
        cultureName = CultureHelper.GetValidCulture(cultureName); // This is safe

        if (request.QueryString.AllKeys.Contains("culture"))
        {
            culture = request.QueryString["culture"];
        }
        else
        {
            culture = cultureName;
        }

        Uitlity.CurrentUICulture = culture;

        base.Initialize(requestContext);
    }
0 голосов
/ 17 апреля 2019

Если вы не используете ControllerActivator, можете использовать класс BaseController и inhеrid от него.

public class BaseController : Controller
{
    public BaseController()
    {
          //Set CurrentCulture and CurrentUICulture of the thread
    }
}

public class HomeController: BaseController    
{
    [HttpGet]
    public ActionResult Index()
    {
        //..............................................
    }
}
...