Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Server-side validation localization differs from client-side

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

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

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:

<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:

<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.

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.

So I tried to set the culture on begin request (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"?

Thank you in advance.

like image 920
Linus Caldwell Avatar asked Jul 17 '26 10:07

Linus Caldwell


1 Answers

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.

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