Pour l'application Web multilingue ASP.NET MVC 3, je détermine le Thread.CurrentThread.CurrentCulture
et Thread.CurrentThread.CurrentUICulture
sur l'usine du contrôleur comme suit:
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);
}
}
Le code ci-dessus a presque un an maintenant! Alors, j'ouvre pour des suggestions.
Et je l'enregistre sur le fichier Global.asax comme:
ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());
Cela fonctionne bien, mais je ne sais pas si c'est la meilleure pratique et le meilleur endroit pour faire ce type d'action.
Je n'ai pas creusé le rôle principal de ControllerFactory
et je ne peux pas le comparer avec ActionFilterAttribute
.
Que pensez-vous du meilleur endroit pour faire ce type d'action?
J'ai utilisé un ActionFilter
global pour cela, mais récemment j'ai réalisé que définir la culture actuelle dans la méthode OnActionExecuting
est trop tard dans certains cas. Par exemple, lorsque le modèle après POST arrive au contrôleur, ASP.NET MVC crée des métadonnées pour le modèle. Elle se produit avant l'exécution de toute action. Par conséquent, DisplayName
les valeurs d'attribut et les autres éléments d'annotation de données sont gérés à l'aide de la culture par défaut à ce stade.
Finalement, j'ai déplacé la définition de la culture actuelle vers l'implémentation personnalisée IControllerActivator
, et cela fonctionne comme un charme. Je suppose que c'est presque la même chose du point de vue du cycle de vie des demandes pour héberger cette logique dans l'usine de contrôleurs personnalisés, comme vous l'avez fait aujourd'hui. C'est beaucoup plus fiable que l'utilisation de ActionFilter
global.
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()));
}
}
Je sais qu'un anser a déjà été sélectionné. L'option que nous avons utilisée était de simplement initialiser la culture actuelle du thread dans l'événement OnBeginRequest pour l'application. Cela garantit que la culture est découverte à chaque demande
public void OnBeginRequest(object sender, EventArgs e)
{
var culture = YourMethodForDiscoveringCulutreUsingCookie();
System.Threading.Thread.CurrentThread.CurrentCulture = culture;
System.Threading.Thread.CurrentThread.CurrentUICulture = culture;
}
Un autre endroit pour mettre cela serait de mettre ce code dans la méthode OnActionExecuting d'un ActionFilter personnalisé, qui peut être enregistré dans la collection GlobalFilters:
http://weblogs.asp.net/gunnarpeipman/archive/2010/08/15/asp-net-mvc-3-global-action-filters.aspx
Au lieu de remplacer OnActionExecuting
vous pouvez remplacer Initialize
ici comme ceci
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);
}
Si vous n'utilisez pas ControllerActivator, vous pouvez utiliser la classe BaseController et ne rien y cacher.
public class BaseController : Controller
{
public BaseController()
{
//Set CurrentCulture and CurrentUICulture of the thread
}
}
public class HomeController: BaseController
{
[HttpGet]
public ActionResult Index()
{
//..............................................
}
}