StevenQ
StevenQ

Reputation: 192

MVC Model Binding for DateTime is different using GET or POST

I encountered following unwanted behaviour while using "Remote" validation attribute for a certain DateTime Model property.

Server-side, my Application Culture is defined as described below:

protected void Application_PreRequestHandlerExecute()
{
    if (!(Context.Handler is IRequiresSessionState)){ return; }
    Thread.CurrentThread.CurrentCulture = new CultureInfo("nl-BE");
    Thread.CurrentThread.CurrentUICulture = new CultureInfo("nl-BE");
}

Client-side, my Application Culture is defined as described below:

Globalize.culture("nl-BE");

Case 1:

Case 2:

Am I missing some configuration for making the "standard" GET remote validation work as desired?

Upvotes: 7

Views: 2777

Answers (1)

Li0liQ
Li0liQ

Reputation: 11264

When binding data for GET, InvariantCulture is used(which is "en-US"), whereas for POST Thread.CurrentThread.CurrentCulture is. The reason behind is that GET urls may be shared by users and hence should be invariant. Whereas POST is never shared and it is safe to use server's culture for binding there.

If you are sure your application does not need the option of sharing urls between people coming from different countries, you are safe to create your own ModelBinder that will force to use server locale even for GET requests.

Here is the sample how it may look like in Global.asax.cs:

protected void Application_Start()
{
    /*some code*/

    ModelBinders.Binders.Add(typeof(DateTime), new DateTimeModelBinder());
    ModelBinders.Binders.Add(typeof(DateTime?), new DateTimeModelBinder());
}

/// <summary>
/// Allows to pass date using get using current server's culture instead of invariant culture.
/// </summary>
public class DateTimeModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        var date = valueProviderResult.AttemptedValue;

        if (String.IsNullOrEmpty(date))
        {
            return null;
        }

        bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);

        try
        {
            // Parse DateTimeusing current culture.
            return DateTime.Parse(date);
        }
        catch (Exception)
        {
            bindingContext.ModelState.AddModelError(bindingContext.ModelName, String.Format("\"{0}\" is invalid.", bindingContext.ModelName));
            return null;
        }
    }
}

Upvotes: 11

Related Questions