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

本文关键字:客户端 不同于 本地化 验证 服务器端 | 更新日期: 2023-09-27 18:17:22

虽然这也可能涉及到其他主题,但我只是在验证中遇到以下问题:

模型注释、控制器和操作

我使用来自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。配置包含

<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强制服务器端验证会呈现以下未本地化的验证消息,而data属性仍然是本地化的:
<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>

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

What Did I Try?

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

这让我相信服务器端和客户端从资源中获取消息的时间可能是不同的。也许服务器端在执行动作之前做了,这意味着CultureFilter.OnActionExecuting()在那之后被调用,在这种情况下当然是太晚了。

所以我尝试在开始请求(global.asax):

上设置区域性
protected void Application_BeginRequest()
{
    Thread.CurrentThread.CurrentUICulture = new CultureInfo("de");
}

好吧,那起作用了。但我真的认为这是一个丑陋的解决方案。所以…

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

服务器端验证在过滤器设置区域性之前从资源中获取消息,这是真的吗?如果不是,我做错了什么?如果是,是否有另一个比全局更清晰的选项来设置区域性。asax"黑客"?

提前感谢。

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

问题是DefaultModelBinder在执行Filter之前创建模型,并且在模型创建期间添加了验证错误(此时文化是web.config文件中定义的en-US)。

一种选择可能是创建自定义ModelBinder(并将其注册为DefaultModelBinder)并覆盖OnPropertyValidating()方法以设置区域性。

当你在Application_BeginRequest方法中基于用户设置设置文化时,我相信你是对的。它甚至不是一个黑客。您可能希望在请求生命周期中尽早将区域性设置为正确的区域性。

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

阿米特*

多亏了Stephen Muecke的回答,他把我推向了正确的方向,我意识到我可以实现更多的过滤器接口。在本文中可以找到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中使用Application_BeginRequest更干净。asax和我认为,特别是在IAuthenticationFilter中,设置文化在那里比在模型绑定上更好。