Ahora que estoy metido de lleno en un desarrollo con ASP.NET MVC 4, pensé que sería buena idea leer un buen libro sobre el mismo. Mi elección fue Pro ASP.NET MVC 4. El libró me encantó y lo recomiendo.
En el capítulo “Model Binding” (obligado título para un capítulo de un libro que hable sobre ASP.NET MVC) me chocó mucho el siguiente texto (que cito literalmente)
“The DefaultModelBinder class use different culture settings to perform type conversions from different areas of the request data. The values that are obtained from URLs (the routing and query string data) are converted using culture-insensitive parsing, but values obtained from form data are converted taking cultureinto account.
The most common problem that this causes relates to DateTime values. Culture-insensitive dates are expected to be in the universal format yyyy-mm-dd. Form date values are expected to be in the format specified by the server. This means that a server set to the UK culture will expected dates to be in the form dd-mm-yyyy, whereas a server set to the US culture will expect the format mm-dd-yyyy, though in either case yyyy-mm-dd is acceptable too.
A date value won’t be converted if it isn’t in the right format. This means that we must make sure that all dates included in the URL are expressed in the universal format. We must also be careful when processing date values that users provide—the default binder assumes that the user will express dates in using the format of the server culture, something that unlikely to always happen in an MVC application that has international users.”
Como por suerte o por desgracia, todas las aplicaciones que desarrollamos en la empresa tiene que soportan internacionalización, el tema de formato de fechas y números es un tema que me preocupa especialmente.
El párrafo citado anterior viene a decir lo siguiente:
- Los datos provenientes de la url (querystring y route values) son culture-insensitive. Es decir, esperan un formato determinado con independencia de la cultura establecida en el servidor.
- Los datos provenientes del form son culture-sensitives. Esto es que sí tienen en cuenta la cultura del servidor.
Vamos a hacer unos pruebas para confirmar esto y verlo en directo. La cultura del servidor será es-ES (haciendo patria) y simplemente crearemos un acción como la siguiente:
public ActionResult Index(decimal? numero, DateTime? fecha)
{
return View();
}
Ahora y con la ayuda de ScratchPad probaremos el binding de fechas y números.
POST http://localhost:6319/ HTTP/1.1 Numero=1,5&Fecha=31%2F12%2F2013 |
Todo perfecto, tanto 1,5 como 31/12/2013 son formatos válidos para es-ES. |
… Numero=1.5&Fecha=13%2F31%2F2013 |
Ninguna de los 2 parámetros cumple con el formato esperado, error. |
… Numero=1,5&Fecha=2013%2F12%2F31 |
Sorprendentemente, aunque form sea culture-sensitive, también acepta el formato yyyy-mm-dd para las fechas. |
GET http://localhost:6319/?numero=1,5&fecha=31-12-2013 HTTP/1.1 |
Ninguna de los 2 parámetros cumple con el formato esperado, error. |
GET http://localhost:6319/?numero=1.5&fecha=2013-12-31 HTTP/1.1 |
Ningún problema, especial atención el formato de la fecha: yyyy-mm-dd |
GET http://localhost:6319/?numero=1.5&fecha=12-31-2013 HTTP/1.1 |
Otra sorpresa, aunque se suponía que el formato de fecha para url tenía que ser yyyy-mm-dd, aparentemente también acepta mm-dd-yyyy |
Con esta situación está claro que bindear números y fechas y soportan internacionalización en tu aplicación se va a convertir en una pesadilla si utilizamos sólo y exclusivamente DefaultModelBinder. Es por ello, que resulta necesario crear unos binders personalizados para los tipos Decimal y DateTime.
El código es el siguiente:
ModelBinders.Binders.Add(typeof(DateTime), new DateTimeModelBinder());ModelBinders.Binders.Add(typeof(DateTime?), new DateTimeModelBinder());ModelBinders.Binders.Add(typeof(Decimal), new DecimalModelBinder());ModelBinders.Binders.Add(typeof(Decimal?), new DecimalModelBinder());
Con esto, además del comportamiento predeterminado del DefaultModelBinder, ahora tanto url (querystring y route values) como form serán culture-sensitive.
Un saludo!