为多语言ASP.NET MVC Web应用程序设置CurrentCulture的最佳位置

时间:2011-11-22 12:05:37

标签: asp.net-mvc asp.net-mvc-3 action-filter controller-factory

对于多语言ASP.NET MVC 3 Web应用程序,我正在确定控制器工厂上的Thread.CurrentThread.CurrentCultureThread.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 个答案:

答案 0 :(得分:56)

我为此使用了全局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()));
    }
}

答案 1 :(得分:7)

我知道已经选择了一个anser。我们使用的选项是在Application的OnBeginRequest事件中初始化线程当前文化。这确保了每次请求都能发现文化

public void OnBeginRequest(object sender, EventArgs e)
{
   var culture = YourMethodForDiscoveringCulutreUsingCookie();
   System.Threading.Thread.CurrentThread.CurrentCulture = culture;
   System.Threading.Thread.CurrentThread.CurrentUICulture = culture;
}

答案 2 :(得分:4)

另一个放置它的地方是将该代码放在自定义ActionFilter的OnActionExecuting方法中,该方法可以在GlobalFilters集合中注册:

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

答案 3 :(得分:3)

而不是覆盖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);
    }

答案 4 :(得分:0)

如果您不使用ControllerActivator,则可以使用BaseController类并从中隐蔽。

<label>

                    <div class="drop1">
                        <label for="drop1">Recipes
                          <input type="checkbox" id="drop1">
                          <div class="drop-menu">
                            <a href="">Meat Recipes</a>
                            <a href="">Veggie Recipes</a>
                            <a href="">Deserts</a>
                          </div>
                        </label>
                    </div>