开发者

CultureInfo issue with Modelbinding double in asp.net-mvc(2)

In my Jquery script I post two doubles using the browser's CultureInfo (en-UK) that uses the .as a fraction separator. My MVC app is running on a server with locale nl-BE using the , as a fraction separator.

[A开发者_如何转开发cceptVerbs(HttpVerbs.Post)]
public JsonResult GetGridCell(double longitude, double latitude)
{
    var cell = new GridCellViewModel { X = (int)Math.Round(longitude, 0), Y = (int)Math.Round(latitude, 0) };
    return Json(cell);
}

The modelbinding fails because of the parsing issue.

I think it would be best to have my javascript set to en-UK and the same for the modelbinding in my MVC app. But I don't know how to do either.

Any suggestions?


I'm not sure how far localisation goes with the default model binder (DefaultModelBinder), but you can easily create a binder yourself that can handle the culture specific parsing of the data, e.g, create a new class, let's call it the DoubleModelBinder, copypasta the following:

public class DoubleModelBinder : IModelBinder
{
    /// <summary>
    /// Binds the value to the model.
    /// </summary>
    /// <param name="controllerContext">The current controller context.</param>
    /// <param name="bindingContext">The binding context.</param>
    /// <returns>The new model.</returns>
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var culture = GetUserCulture(controllerContext);

        string value = bindingContext.ValueProvider
                           .GetValue(bindingContext.ModelName)
                           .ConvertTo(typeof(string)) as string;

        double result = 0;
        double.TryParse(value, NumberStyles.Any, culture, out result);

        return result;
    }

    /// <summary>
    /// Gets the culture used for formatting, based on the user's input language.
    /// </summary>
    /// <param name="context">The controller context.</param>
    /// <returns>An instance of <see cref="CultureInfo" />.</returns>
    public CultureInfo GetUserCulture(ControllerContext context)
    {
        var request = context.HttpContext.Request;
        if (request.UserLanguages == null || request.UserLanguages.Length == 0)
            return CultureInfo.CurrentUICulture;

        return new CultureInfo(request.UserLanguages[0]);
    }
}

Now, what we are doing here, is establishing our own language-aware double-parser. When we implement the IModelBinder interface, we need to create a BindModel method. This is where the meat of the it is done, but before we can parse anything, we need to get an IFormatProvider based on the browser's language. So, we use the GetUserCulture method to try and ready the browser's language. If we can't revert to the current culture.

When we have that, we are then in a position to parse the value. We first grab it from the ValueProvider (which is really a composite of many value providers, e.g. from the Form collection, Request collection, etc.), and then we parse it using the discovered IFormatProvider, which is the CultureInfo we now have.

Once you've done that, it's pretty trivial to add it to the model binder collection;

ModelBinder.Binders[typeof(Double)] = new DoubleModelBinder();

Try that and see if that helps.


ModelBinding uses CurrentCulture to parse values. Thats understandable, because the user might enter a date or decimal into a textbox and the value would be parsed correctly.

But I still think most developers see it the way you see it: They want that all values are parsed by using the same culture no matter what language the user uses. They want to display values in the format of the user but enter values in a neutral format (InvariantCulture).

Thats why I set the CurrentCulture in Application.BeginRequest to CultureInfo.InvariantCulture. By that all Binding uses the invariant Culture. If you later want to use Ressources or format values in the language of the browser you have to switch back to the language of the user, by setting CurrentCulture to the language of the user again. I do this in an action filter.

EDIT:

The OP corrected me in that only Form submissions are culture aware: thats true. See the source for ValueProviderDictionary:PopulateDictionary where it is documented:

   We use this order of precedence to populate the dictionary:
   1. Request form submission (should be culture-aware)
   2. Values from the RouteData (could be from the typed-in URL or from the route's default values)
   3. URI query string
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜