2012-03-02 17 views
8

Estoy enviando fechas desde mi aplicación web en formato UTC, pero cuando las recibo en el servidor, el serializador JSon (que probablemente se usa configurando su modelo) lo hace en una fecha local & hora con DateTimeKind. Local relativo a la zona horaria del servidor.¿Cómo decirle a ASP.Net MVC que todas las fechas entrantes deserializadas de JSon deberían ser UTC?

Cuando hago un DateTime.ToUniversalTime() obtengo la fecha UTC adecuada, así que esto no es un problema. La conversión funciona correctamente y las fechas se envían como deberían ... pero ... No me gusta hacer una llamada a 'ToUniversalTime()' en cada fecha de mi modelo antes de almacenarlo en una base de datos. Esto es propenso a errores y fácil de olvidar cuando tienes una gran aplicación.

Así que aquí está la pregunta: ¿Hay alguna manera de decirle a MVC que las fechas de entrada siempre deben expresarse en formato UTC?

+0

parece que el deserializer está haciendo su trabajo bien, si los valores en el objeto DateTime son correctos. Las fechas pueden ser difíciles de manejar si comienza a tratar algunas como especiales en el servidor. –

+1

@dtryon: No, creo que conservarlos como UTC tiene mucho más sentido. Los tiempos locales pueden ser fácilmente ambiguos, por lo que el deserializador puede estar * perdiendo información * aquí, lo que sin duda es un pecado capital. –

+0

@JonSkeet, pero mientras ToUniversalTime() devuelva el UTC correcto, ¿no se está expresando correctamente? –

Respuesta

2

Después de excavar un poco más, he encontrado la manera de hacer que esto funcione.

El problema no era tanto el serializador, sino el problema de que las fechas del modelo no se expresan en UTC sino en hora local. ASP.Net le permite crear carpetas de modelo personalizadas y creo que esta es la clave para cambiar las fechas a UTC una vez que se hayan deserializado.

He utilizado el código siguiente para hacer este trabajo, puede haber algunos errores de limar, pero obtendrá la idea:

public class UtcModelBinder : DefaultModelBinder 
{ 
    protected override void SetProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor, object value) 
    { 
    HttpRequestBase request = controllerContext.HttpContext.Request; 

    // Detect if this is a JSON request 
    if (request.IsAjaxRequest() && 
     request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase)) 
    { 
     // See if the value is a DateTime 
     if (value is DateTime) 
     { 
     // This is double casting, but since it's a value type there's not much other things we can do 
     DateTime dateValue = (DateTime)value; 

     if (dateValue.Kind == DateTimeKind.Local) 
     { 
      // Change it 
      DateTime utcDate = dateValue.ToUniversalTime(); 
      if (!propertyDescriptor.IsReadOnly && propertyDescriptor.PropertyType == typeof(DateTime)) 
      propertyDescriptor.SetValue(bindingContext.Model, utcDate); 

      return; 
     } 
     } 
    } 

    // Fall back to the default behavior 
    base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value); 

    } 
} 
Cuestiones relacionadas