zona horas horaria conversor c# wcf json datetime serialization

c# - horas - ¿Por qué no se serializa DateTime.MinValue en zonas horarias antes de UTC?



datetime zona horaria c# (6)

Creo que una manera más elegante es ordenar al serializador que no emita el valor predeterminado para los campos DateTime. Esto ahorrará un byte durante la transferencia y algo de procesamiento al serializar para los campos que no tiene ningún valor para ellos. Ejemplo:

[DataContract] public class Document { [DataMember] public string Title { get; set; } [DataMember(IsRequired = false, EmitDefaultValue = false)] public DateTime Modified { get; set; } }

o puedes usar Nullables. Ejemplo:

[DataContract] public class Document { [DataMember] public string Title { get; set; } [DataMember] public DateTime? Modified { get; set; } }

Todo depende de los requisitos y restricciones que pueda tener en su proyecto. A veces no puedes simplemente cambiar los tipos de datos. En ese caso, aún puede aprovechar el atributo DataMember y mantener intactos los tipos de datos.

En el ejemplo anterior, si tiene un new Document() { Title = "Test Document" } en el servidor, cuando se serialice en JSON le dará {"Title": "Test Document"} por lo que será más fácil tratar con en JavaScript o cualquier otro cliente en el otro lado del cable. En JavaScript si usa JSON.Parse () y trata de leerlo, volverá a estar undefined . En los idiomas escritos, tendrá el valor predeterminado para esa propiedad según el tipo (que generalmente es el comportamiento esperado).

library.GetDocument(id).success(function(raw){ var document = JSON.Parse(raw); var date = document.date; // date will be *undefined* ... }

Estoy teniendo problemas con un servicio WCF REST. El objeto de conexión que trato de devolver tiene ciertas propiedades no establecidas, lo que da como resultado DateTime.MinValue para las propiedades de tipo DateTime. El servicio devuelve un documento vacío (con el estado HTTP 200 ???). Cuando trato de llamar a la serialización JSON, la excepción que se lanza es:

SerializationException: los valores DateTime que son mayores que DateTime.MaxValue o menores que DateTime.MinValue cuando se convierten a UTC no se pueden serializar a JSON.

Esto se puede reproducir ejecutando el siguiente código en una aplicación de consola:

DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(DateTime)); MemoryStream m = new MemoryStream(); DateTime dt = DateTime.MinValue; // throws SerializationException in my timezone ser.WriteObject(m, dt); string json = Encoding.ASCII.GetString(m.GetBuffer()); Console.WriteLine(json);

¿Por qué es este comportamiento? Creo que está relacionado con mi zona horaria (GMT + 1). Como DateTime.MinValue es predeterminado (DateTime), esperaría que esto se pueda serializar sin problemas.

¿Algún consejo sobre cómo hacer que mi servicio REST se comporte? No quiero cambiar mi DataContract.


El problema principal es DateTime.MinValue tiene el tipo DateTimeKind.Unspecified . Se define como:

MinValue = new DateTime(0L, DateTimeKind.Unspecified);

Pero esto no es un problema real, esta definición genera problemas durante la serialización. Serialización JSON DateTime hecho a través de:

System.Runtime.Serialization.Json.JsonWriterDelegator.WriteDateTime(DateTime value)

Desafortunadamente se define como:

... if (value.Kind != DateTimeKind.Utc) { long num = value.Ticks - TimeZone.CurrentTimeZone.GetUtcOffset(value).Ticks; if ((num > DateTime.MaxValue.Ticks) || (num < DateTime.MinValue.Ticks)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString("JsonDateTimeOutOfRange"), new ArgumentOutOfRangeException("value"))); } } ...

Por lo tanto, no tiene en cuenta No Unspecified y lo trata como Local . Para evitar esta situación, puede definir su propia constante:

MinValueUtc = new DateTime(0L, DateTimeKind.Utc);

o

MinValueUtc = DateTime.MinValue.ToUniversalTime();

Se ve raro, por supuesto, pero ayuda.


Intenta agregar esto en cualquier miembro de DateTime

[DataMember(IsRequired = false, EmitDefaultValue = false)]

La mayoría de estos errores ocurren porque el valor predeterminado de la datetime es DateTime.MinValue que es del año 1 y la serialización JSON es del año 1970.


Podrías arreglar eso durante la serialización a través del atributo OnSerializing y algo de reflexión:

[OnSerializing] public void OnSerializing(StreamingContext context) { var properties = this.GetType().GetProperties(); foreach (PropertyInfo property in properties) { if (property.PropertyType == typeof(DateTime) && property.GetValue(this).Equals(DateTime.MinValue)) { property.SetValue(this, DateTime.MinValue.ToUniversalTime()); } } }


Si su zona horaria es GMT + 1, entonces el valor UTC de DateTime.MinValue en su zona horaria va a ser una hora menor que DateTime.MinValue .


usando este constructor:

public DataContractJsonSerializer(Type type, IEnumerable<Type> knownTypes, int maxItemsInObjectGraph, bool ignoreExtensionDataObject, IDataContractSurrogate dataContractSurrogate, bool alwaysEmitTypeInformation)

código de ejemplo:

DataContractJsonSerializer serializer = new DataContractJsonSerializer(o.GetType(), null, int.MaxValue, false, new DateTimeSurrogate(), false); public class DateTimeSurrogate : IDataContractSurrogate { #region IDataContractSurrogate 成员 public object GetCustomDataToExport(Type clrType, Type dataContractType) { return null; } public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType) { return null; } public Type GetDataContractType(Type type) { return type; } public object GetDeserializedObject(object obj, Type targetType) { return obj; } public void GetKnownCustomDataTypes(System.Collections.ObjectModel.Collection<Type> customDataTypes) { } public object GetObjectToSerialize(object obj, Type targetType) { if (obj.GetType() == typeof(DateTime)) { DateTime dt = (DateTime)obj; if (dt == DateTime.MinValue) { dt = DateTime.MinValue.ToUniversalTime(); return dt; } return dt; } if (obj == null) { return null; } var q = from p in obj.GetType().GetProperties() where (p.PropertyType == typeof(DateTime)) && (DateTime)p.GetValue(obj, null) == DateTime.MinValue select p; q.ToList().ForEach(p => { p.SetValue(obj, DateTime.MinValue.ToUniversalTime(), null); }); return obj; } public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData) { return null; } public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit) { return typeDeclaration; } #endregion }