服务器端验证本地化与客户端不同

时间:2014-08-10 01:06:06

标签: c# asp.net asp.net-mvc asp.net-mvc-3 localization

虽然这可能与其他主题有关,但我只是在验证方面遇到以下问题:

模型注释,控制器和动作

我使用System.ComponentModel.DataAnnotations的验证属性。该模型看起来像

public class NewUserModel
{
    [Required]
    public string Username { get; set; }
}

所以,没什么特别的。据此,一个非常默认的控制器动作

public ActionResult New()
{
    return View(new NewUserModel());
}

和视图

@using (Html.BeginForm())
{
    @Html.LabelFor(m => m.Username)
    @Html.EditorFor(m => m.Username)
    @Html.ValidationMessageFor(m => m.Username)
    <button type="submit">save</button>
}

使用过滤器设置文化

根据用户首选项,通过以下过滤器设置文化

public class CultureFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        // simplified for this example
        Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("de");
    }
}

使用

在global.asax中注册
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new CultureFilter());
}

默认语言为英语,因此web.config包含

<globalization culture="en-US" uiCulture="en"/>

完成后,客户端验证工作完美。不显眼的jQuery验证的数据属性已经过本地化,您可以在生成的HTML中看到:

<input data-val="true"
       data-val-required="Das Feld Username ist erforderlich."
       id="Username" name="Username" type="text" value="" />

问题:没有本地化的服务器端验证

麻烦的是,通过在未本地化验证消息后禁用JavaScript呈现来强制进行服务器端验证,而数据属性仍然是本地化的:

<input data-val="true"
       data-val-required="Das Feld Username ist erforderlich."
       id="Username" name="Username" type="text" value="" />
<span class="field-validation-error" data-valmsg-for="Username"
      data-valmsg-replace="true">The Username field is required.</span>

看起来很有趣,不是吗? ; - )

我尝试了什么?

首先,我检查了服务器端文化是否由web.config设置。是的。如果我将<globalization/>属性更改为德语文化(或者只是按系统语言删除节点是德语),服务器端验证消息也是德语。

这让我相信服务器端和客户端从资源中获取消息的时间可能会有所不同。也许服务器端在执行操作之前执行它,这意味着在此之后调用CultureFilter.OnActionExecuting(),在这种情况下当然为时已晚。

所以我尝试在开始请求(global.asax)上设置文化:

protected void Application_BeginRequest()
{
    Thread.CurrentThread.CurrentUICulture = new CultureInfo("de");
}

嗯,这就是诀窍。但我真的认为这是一个丑陋的解决方案。所以......

问题:我是对的,我还有其他选择吗?

是否真的,服务器端验证在过滤器设置文化之前从资源获取消息?如果没有,我做错了什么?如果是,那么设置文化的另一个更清洁的选择是否比global.asax“hack”更清晰?

提前谢谢。

3 个答案:

答案 0 :(得分:1)

问题是DefaultModelBinder在执行Filter之前创建了模型,并且在创建模型期间创建了验证错误(此时文化为{{1}在en-US文件中定义。

一个选项可能是创建自定义web.config(并将其注册为ModelBinder)并覆盖DefaultModelBinder方法来设置文化。

答案 1 :(得分:0)

我相信在Application_BeginRequest方法中根据用户设置设置文化时,你是对的。它甚至都不是黑客。您希望在请求生命周期中尽早将您的文化设置为正确的文化。

虽然应该注意的一件事是,对于单个url请求,此Application_BeginRequest将被调用超过1次,其他文件如图像和东西。因此加载用户详细信息的任务应该只进行一次。或者一些编程工作,以便在多个请求期间缓存用户首选项,并且仅当用户更改他/她的首选项时才应重新加载缓存

ameet

答案 2 :(得分:0)

感谢Stephen Muecke's answer,他推动我朝着正确的方向前进,我意识到我可以实现更多的过滤器接口。可以在this article中找到有关MVC生命周期的精彩概述。它指出在模型绑定发生之前调用IAuthenticationFilterIAuthorizationFilter实现。

我决定在我的案例中使用这些接口(IAuthorizationFilter因为IAuthenticationFilter在MVC 3中不可用)CultureFilter

// would use IAuthenticationFilter in MVC 5
public class CultureFilter : IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext filterContext)
    {
        // simplified for this example
        Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("de");
    }
}

这可能不是最佳做法,但在我看来,它比在global.asax中使用Application_BeginRequest更清晰,我认为,尤其是IAuthenticationFilter,设置文化是更好的地方而不是模型绑定。