在asp.net-mvc中使用Modelbinding double的CultureInfo问题(2)

时间:2010-07-02 19:39:45

标签: c# .net asp.net-mvc-2 cultureinfo model-binding

在我的Jquery脚本中,我使用浏览器的CultureInfo(en-UK)发布两个双打,它使用.作为分数分隔符。我的MVC应用程序在具有区域设置nl-BE的服务器上运行,使用,作为分数分隔符。

[AcceptVerbs(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);
}

由于解析问题,模型绑定失败。

我认为最好将我的javascript设置为en-UK,并将其与我的MVC应用中的模型绑定相同。但我不知道该怎么办。
有什么建议吗?

2 个答案:

答案 0 :(得分:8)

我不确定本地化与默认模型绑定器(DefaultModelBinder)的距离有多远,但您可以自己轻松创建一个可以处理特定于文化的数据解析的绑定器,例如,创建一个新类,让我们称之为以下是DoubleModelBinder,copypasta:

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]);
    }
}

现在,我们在这里做的是建立我们自己的语言感知双解析器。当我们实现IModelBinder接口时,我们需要创建一个BindModel方法。这就是它的核心所在,但在我们解析任何东西之前,我们需要根据浏览器的语言获得IFormatProvider。因此,我们使用GetUserCulture方法尝试并准备好浏览器的语言。如果我们不能回归当前的文化。

当我们有了这个时,我们就可以解析这个价值了。我们首先从ValueProvider中获取它(它实际上是许多值提供者的组合,例如来自Form集合,Request集合等),然后我们使用发现的IFormatProvider解析它,这是我们现在拥有的CultureInfo。 / p>

完成后,将它添加到模型活页夹集合中非常简单;

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

尝试一下,看看是否有帮助。

答案 1 :(得分:1)

ModelBinding使用CurrentCulture来解析值。这是可以理解的,因为用户可能会在文本框中输入日期或小数,并且值将被正确解析。

但我仍然认为大多数开发人员都会以你看到的方式看待它:他们希望无论用户使用何种语言,都使用相同的文化来解析所有值。他们希望以用户的格式显示值,但以中性格式输入值(InvariantCulture)。

这就是我将Application.BeginRequest中的CurrentCulture设置为CultureInfo.InvariantCulture的原因。所有Binding使用不变的文化。如果您以后想要使用浏览器语言中的Ressources或格式值,则必须通过将CurrentCulture再次设置为用户的语言来切换回用户的语言。我在动作过滤器中执行此操作。

编辑:

OP纠正了我,因为只有表单提交才具有文化意识:这是真的。请参阅ValueProviderDictionary的源代码:PopulateDictionary,其中记录了它:

   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