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

时间:2021-08-22 16:10:05

Whilst this may concern to other topics as well, I'm just heading the following trouble with validation:

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

Model Annotation, Controller and Action

I use validation attributes from System.ComponentModel.DataAnnotations. The model looks like

我使用system . component model . dataannotation的验证属性。这个模型看起来像

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

So, nothing special. According to that, a pretty much default controller action

所以,没什么特别的。根据这一点,一个相当多的默认控制器动作。

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

and the view

和视图

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

Setting Culture With Filter

Based on user preferences, culture is set via following filter

根据用户的喜好,通过以下过滤器设置区域性

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

which is registered in global.asax with

在全球注册。asax与

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new CultureFilter());
}

Default language is english, so the web.config contains

默认语言是英语,所以网络。配置包含

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

With that done, client-side validation works perfectly. Data attributes for unobtrusive jQuery validation are localized as you can see in the resulting HTML:

这样,客户端验证就可以完美地工作了。不引人注目的jQuery验证的数据属性是本地化的,您可以在生成的HTML中看到:

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

The Problem: Server-side Validation Without Localization

The trouble is, that forcing server-side validation by disabling JavaScript renders following unlocalized validation message, while the data attribute is still localized:

问题是,通过禁用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>

Looks pretty funny, doesn't it? ;-)

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

What Did I Try?

First, I checked if the server-side culture is set by web.config. Yes, it is. If I change the <globalization/> attributes to german cultures (or just remove the node as by system language is german), the server-side validation message is german too.

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

This let me believe there might be a difference in times when server-side and client-side take their messages from resources. And maybe the server-side does it prior to executing the action, which means CultureFilter.OnActionExecuting() is called after that, which of course is too late in this case.

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

So I tried to set the culture on begin request (global.asax):

所以我试着按照start的要求设置文化(global.asax):

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

Well, that did the trick. But I really think this is an ugly solution. So...

好吧,这就成功了。但我真的认为这是一个丑陋的解决方案。所以…

The Question: Am I Right and Do I Have Any Other Options?

Is it true, that server-side validation takes the messages from resource before a filter could set the culture? If not, what am I doing wrong? If yes, is there another, cleaner option for setting the culture than the global.asax "hack"?

服务器端验证在过滤器设置区域性之前从资源中获取消息,这是真的吗?如果没有,我做错了什么?如果答案是肯定的,那么还有比全球文化更干净的选择吗?asax“黑客”?

Thank you in advance.

提前谢谢你。

3 个解决方案

#1


1  

The problem is that the DefaultModelBinder creates the model before yourFilter is executed, and its during the creation of the model that validation errors are added (and at this point the culture is en-US as defined in your web.config file.

问题是,DefaultModelBinder在执行过滤器之前创建了模型,并且在创建模型的过程中添加了验证错误(此时,在web中定义的区域性是en-US)。配置文件。

One option may be to create a custom ModelBinder (and register it as the DefaultModelBinder) and override the OnPropertyValidating() method to set the culture.

一个选项可能是创建一个自定义的ModelBinder(并将其注册为DefaultModelBinder),并覆盖OnPropertyValidating()方法来设置区域性。

#2


0  

I believe you are right when you set the culture based on User Settings, in the Application_BeginRequest method. Its not even a hack. You would want your culture to be set to the correct one as early as possible in the request life cycle.

我认为您在Application_BeginRequest方法中基于用户设置设置的区域性设置是正确的。这甚至不是一个黑客。您可能希望在请求生命周期中尽早将您的企业文化设置为正确的企业文化。

Though one thing should be taken care of is that this Application_BeginRequest would be called more than 1 times for a single url request for, other files such as images and stuff. So the task of loading user details, should be done just once. Or some programming effort so that user preferences are cached during multiple requests and cache should be reloaded only when user changes his/her preference

尽管有一件事需要注意,即对于单个url请求,这个Application_BeginRequest会被调用超过1次,其他文件,比如图像和其他文件。因此,加载用户详细信息的任务应该只执行一次。或者进行一些编程工作,以便在多个请求期间缓存用户首选项,只有在用户更改其首选项时才重新加载缓存

ameet

阿米特

#3


0  

Thanks to Stephen Muecke's answer, who pushed me in the right direction, I realized there are more filter interfaces which I could implement. A great overview of the MVC lifecycle can be found in this article. It points out that IAuthenticationFilter and IAuthorizationFilter implementations are invoked before the model binding happens.

感谢Stephen Muecke的回答,他把我推向了正确的方向,我意识到我可以实现更多的过滤器接口。本文对MVC生命周期有一个很好的概述。它指出,在模型绑定发生之前,将调用IAuthenticationFilter和IAuthorizationFilter实现。

I decided to use these interfaces (IAuthorizationFilter in my case because IAuthenticationFilter is not available in MVC 3) for my CultureFilter:

我决定使用这些接口(IAuthorizationFilter,因为我的CultureFilter在MVC 3中没有IAuthenticationFilter):

// 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");
    }
}

This might not be best practice, but in my opinion it's cleaner than using Application_BeginRequest in global.asax and I think, especially with IAuthenticationFilter, setting culture there is the better place than on model binding.

这可能不是最佳实践,但在我看来,它比在全局中使用Application_BeginRequest要干净。asax和我认为,特别是使用IAuthenticationFilter,在那里设置区域性比在模型绑定上更好。

#1


1  

The problem is that the DefaultModelBinder creates the model before yourFilter is executed, and its during the creation of the model that validation errors are added (and at this point the culture is en-US as defined in your web.config file.

问题是,DefaultModelBinder在执行过滤器之前创建了模型,并且在创建模型的过程中添加了验证错误(此时,在web中定义的区域性是en-US)。配置文件。

One option may be to create a custom ModelBinder (and register it as the DefaultModelBinder) and override the OnPropertyValidating() method to set the culture.

一个选项可能是创建一个自定义的ModelBinder(并将其注册为DefaultModelBinder),并覆盖OnPropertyValidating()方法来设置区域性。

#2


0  

I believe you are right when you set the culture based on User Settings, in the Application_BeginRequest method. Its not even a hack. You would want your culture to be set to the correct one as early as possible in the request life cycle.

我认为您在Application_BeginRequest方法中基于用户设置设置的区域性设置是正确的。这甚至不是一个黑客。您可能希望在请求生命周期中尽早将您的企业文化设置为正确的企业文化。

Though one thing should be taken care of is that this Application_BeginRequest would be called more than 1 times for a single url request for, other files such as images and stuff. So the task of loading user details, should be done just once. Or some programming effort so that user preferences are cached during multiple requests and cache should be reloaded only when user changes his/her preference

尽管有一件事需要注意,即对于单个url请求,这个Application_BeginRequest会被调用超过1次,其他文件,比如图像和其他文件。因此,加载用户详细信息的任务应该只执行一次。或者进行一些编程工作,以便在多个请求期间缓存用户首选项,只有在用户更改其首选项时才重新加载缓存

ameet

阿米特

#3


0  

Thanks to Stephen Muecke's answer, who pushed me in the right direction, I realized there are more filter interfaces which I could implement. A great overview of the MVC lifecycle can be found in this article. It points out that IAuthenticationFilter and IAuthorizationFilter implementations are invoked before the model binding happens.

感谢Stephen Muecke的回答,他把我推向了正确的方向,我意识到我可以实现更多的过滤器接口。本文对MVC生命周期有一个很好的概述。它指出,在模型绑定发生之前,将调用IAuthenticationFilter和IAuthorizationFilter实现。

I decided to use these interfaces (IAuthorizationFilter in my case because IAuthenticationFilter is not available in MVC 3) for my CultureFilter:

我决定使用这些接口(IAuthorizationFilter,因为我的CultureFilter在MVC 3中没有IAuthenticationFilter):

// 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");
    }
}

This might not be best practice, but in my opinion it's cleaner than using Application_BeginRequest in global.asax and I think, especially with IAuthenticationFilter, setting culture there is the better place than on model binding.

这可能不是最佳实践,但在我看来,它比在全局中使用Application_BeginRequest要干净。asax和我认为,特别是使用IAuthenticationFilter,在那里设置区域性比在模型绑定上更好。