Globalizing DateTime and Decimal in ASP.NET MVC Using ModelBinder

If you already develop an ASP.NET MVC application in your computer that has some specific culture, pt-BR in my case, and after you publish to a server that has a different one, Azure using en-US in my case, you will have some unexpected results when typing date and decimal values. In this post I will show how to have sure that your application will work as expected in any server. We will accept values corresponding to the culture chosen by the user.

When developing in my machine I can type the date as 24/03/2015 and the decimal as 34,90 and the values will be good. But if I publish to my Azure server, the DateTime is invalid and the decimal has the value 3490. My users want to type in Portuguese format, but in this solution I will show how to parse the values using the culture that the user chosen.

I will suppose that the current culture is in a cookie called “culture”, but you can change the location of this information as you want.

The ASP.NET MVC has the IModelBinder interface, the framework already has ModelBinder for DateTime, Decimal, etc, but we will replace the default.

Let´s create the DateTimeModelBinder, you can see the code below.

public class DateTimeModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var cultureCookie = controllerContext.HttpContext.Request.Cookies["language"];

        var culture = "en-US";

        if (cultureCookie != null)
            culture = cultureCookie.Value;

        DateTime dateTime;

        var valueProvider = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

        if(valueProvider == null)
            return null;

        if (String.IsNullOrEmpty(valueProvider.AttemptedValue))
            return null;

        if(DateTime.TryParse(valueProvider.AttemptedValue, new CultureInfo(culture), DateTimeStyles.None, out dateTime))
        {
            return dateTime;
        }

        bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Invalida date");

        return null;
    }
}

Now let´s create the DecimalModelBinder

public class DecimalModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var cultureCookie = controllerContext.HttpContext.Request.Cookies["language"];

        var culture = "en-US";

        if (cultureCookie != null)
            culture = cultureCookie.Value;

        decimal value;

        var valueProvider = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

        if(valueProvider == null)
            return null;

        if (String.IsNullOrEmpty(valueProvider.AttemptedValue))
            return null;

        if (Decimal.TryParse(valueProvider.AttemptedValue, NumberStyles.Currency, new CultureInfo(culture), out value))
        {
            return value;
        }

        bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Invalida decimal");

        return null;
    }
}

When done, open the Global.asax and replace the default ModelBinders, edit the Application_Start method as below.

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);

    System.Web.Mvc.ModelBinders.Binders.Add(typeof(DateTime), new DateTimeModelBinder());
    System.Web.Mvc.ModelBinders.Binders.Add(typeof(DateTime?), new DateTimeModelBinder());
    System.Web.Mvc.ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
    System.Web.Mvc.ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder());
}

That´s it, now you and your user will have the expected result when typing the values using the culture chosen. You can do the same for double, float, etc.

The next post I will explain how to customize the jQuery validation, we will use the same culture cookie.

Anúncios
Globalizing DateTime and Decimal in ASP.NET MVC Using ModelBinder

2 comentários sobre “Globalizing DateTime and Decimal in ASP.NET MVC Using ModelBinder

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google

Você está comentando utilizando sua conta Google. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s