How to set the culture of the entire ValueProviderResult used when binding the model to a given value?

It turns out that MVC DefaultModelBinder uses different cultures to parse values ​​(e.g. double , DateTime , etc.) for POST and GET requests. Here is more info.

I see that this is controlled by the Culture property of the ValueProviderResult objects that are returned from IValueProvider.GetValue() .

My question is: How can I globally verify that this value is always CultureInfo.InvariantCulture.

I know that I can implement custom value providers and do it this way.

I know that I can implement custom model bindings and do it this way.

I know that I can set the culture in the stream, but, unfortunately, this is not an option in my case.

What I'm looking for is a way to set it up so that even the default binder and existing value providers can analyze in a culture-invariant way, regardless of what the thread culture is configured for.

+6
source share
1 answer

As far as I know, there is no way that would meet your criteria. You will need to do one of what you know you can do (I would say that the most appropriate way would be a custom cost provider).

Reason: All default ValueProviders are hardcoded to use CultureInfo.InvariantCulture or CultureInfo.CurrentCulture .

Here, in particular, the FormValueProvider method does this:

 internal FormValueProvider( ControllerContext controllerContext, IUnvalidatedRequestValues unvalidatedValues ) : base( controllerContext.HttpContext.Request.Form, unvalidatedValues.Form, CultureInfo.CurrentCulture // <--- Grrr, argh ) { } 

The culture is not retrieved anywhere (i.e., the above argument is not used by default, but is used as one culture).

Cultures of different IValueProviders

For reference, this is the default culture for each of IValueProviders:

  • ChildActionValueProvider: InvariantCulture
  • FormValueProvider: CurrentCulture
  • JsonValueProvider: CurrentCulture
  • RouteDataValueProvider: InvariantCulture
  • QueryStringValueProvider: InvariantCulture
  • HttpFileCollectionValueProvider: InvariantCulture

Replacing CurrentCulture IValueProviders

You should not replace FormValueProvider , because, as seen above, it simply calls the constructor of its base class ( NameValueCollectionValueProvider ), which takes the desired culture as an argument.

The initial implementation of FormValueProvider is more complex on the surface than it actually is, with references to internal classes and interfaces. But they are not needed to replace the supplier - they are present only for unit testing.

You only need to call the base constructor (as mentioned above) by passing two NameValueCollection that are easy to get: Request.Forms and the Forms Validation.Unvalidated(Request) property (static method). And set the third argument to the culture you need.

FormValueProviderFactory even simpler.

JsonValueProvider bit more involved - basically you will have to copy the JsonValueProviderFactory source into a new class and change it - because although it allows you to override GetValueProvider() , this method basically consists of calls to other private static .

EDITOR (Petr Ivanov): It worked for me. To make it work, it was not enough to add a custom factory to ValueProviderFactories.Factories , since it is added after FormValueProviderFactory . Instead, I had to replace FormValueProviderFactory with a custom one.

+4
source

Source: https://habr.com/ru/post/949675/


All Articles