web-dev-qa-db-fra.com

Meilleur endroit pour définir CurrentCulture pour les applications Web multilingues ASP.NET MVC

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?

41
tugberk

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()));
    }
}
56
s.ermakovich

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;
}
7
Agile Jedi

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

4
Paul Stovell

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);
    }
3
Hitendra

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()
    {
        //..............................................
    }
}
0
Delyan