Лучшее место для установки CurrentCulture для многоязычных веб-приложений ASP.NET MVC
Для многоязычного веб-приложения ASP.NET MVC 3 я определяю Thread.CurrentThread.CurrentCulture
и Thread.CurrentThread.CurrentUICulture
на контроллере factory следующим образом:
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
.
Что вы думаете о лучшем месте для этого типа действий?
Ответы
Ответ 1
Я использовал глобальный ActionFilter
для этого, но недавно я понял, что установка текущей культуры в методе OnActionExecuting
в некоторых случаях слишком поздняя. Например, когда модель после запроса POST приходит к контроллеру, ASP.NET MVC создает метаданные для модели. Это происходит до того, как будут выполнены какие-либо действия. В результате значения атрибута DisplayName
и другие данные аннотации данных обрабатываются с использованием культуры по умолчанию в этой точке.
В конце концов я переместил настройку текущей культуры в пользовательскую реализацию IControllerActivator
, и она работает как шарм. Я полагаю, что это почти то же самое с точки зрения жизненного цикла запроса для размещения этой логики в пользовательском контроллере factory, как и сегодня. Это гораздо надежнее, чем использование глобального 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()));
}
}
Ответ 2
Я знаю, что anser уже выбран. Опция, которую мы использовали, это просто инициализировать текущую культуру потока в событии OnBeginRequest для приложения. Это обеспечивает обнаружение культуры с каждым запросом
public void OnBeginRequest(object sender, EventArgs e)
{
var culture = YourMethodForDiscoveringCulutreUsingCookie();
System.Threading.Thread.CurrentThread.CurrentCulture = culture;
System.Threading.Thread.CurrentThread.CurrentUICulture = culture;
}
Ответ 3
Альтернативным местом для этого было бы поместить этот код в метод OnActionExecuting пользовательского ActionFilter, который может быть зарегистрирован в коллекции GlobalFilters:
http://weblogs.asp.net/gunnarpeipman/archive/2010/08/15/asp-net-mvc-3-global-action-filters.aspx
Ответ 4
Вместо переопределения 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);
}
Ответ 5
Если вы не используете 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()
{
//..............................................
}
}