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:
Model Property
[Remote("IsDateValid", "Home")]
public DateTime? MyDate { get; set; }
Controller Action
public JsonResult IsDateValid(DateTime? MyDate)
{
// some validation code here
return Json(true, JsonRequestBehavior.AllowGet);
}
IsDateValid
method, a date entered in the UI as 05/10/2013
(October 5th 2013) is incorrectly interpreted as 10/05/2013
(May 10th, 2013)Case 2:
Model Property
[Remote("IsDateValid", "Home", HttpMethod = "POST")]
public DateTime? MyDate { get; set; }
Controller Action
[HttpPost]
public JsonResult IsDateValid(DateTime? MyDate)
{
// some validation code here
return Json(true);
}
IsDateValid
method, a date entered in the UI as 05/10/2013
(October 5th 2013) is correctly interpreted as 05/10/2013
(October 5th 2013)Am I missing some configuration for making the "standard" GET remote validation work as desired?
How Model Binding Works. Model binding is a simplistic way to correlate C# code with an HTTP request. The model binding applies to transforming the HTTP request data in the query's form string and form collection of the action method parameters. We can consider these parameters to be primitive type or complex type.
So the two-way data binding means we can perform both read and write operations.
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;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With