WCF DataContractJsonSerializer и установка объектов DateTime в UTC?

#c# #asp.net #wcf #datetime #serialization

#c# #asp.net #wcf #datetime #сериализация

Вопрос:

Существует ли универсальный способ указать DataContractJsonSerializer использовать UTC для дат? В противном случае я должен добавить .ToUniversalTime() для всех моих экземпляров date. Возможно ли это? Причина в том, что значения даты по умолчанию соответствуют DateTimeKind.Локальный и добавление смещений к результату JSON. Универсализация дат помогает, но можно ли это сделать на глобальном уровне? Спасибо.

Ответ №1:

Нет способа сделать это напрямую на глобальном уровне — примитивные типы (такие как DateTime) не могут быть «заменены». Возможный обходной путь заключается в использовании какого-либо отражения вместе с суррогатом для изменения полей DateTime (или свойств) в объекте при его сериализации, как показано в примере ниже.

 public class StackOverflow_6100587_751090
{
    public class MyType
    {
        public MyTypeWithDates d1;
        public MyTypeWithDates d2;
    }
    public class MyTypeWithDates
    {
        public DateTime Start;
        public DateTime End;
    }
    public class MySurrogate : IDataContractSurrogate
    {
        public object GetCustomDataToExport(Type clrType, Type dataContractType)
        {
            throw new NotImplementedException();
        }

        public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
        {
            throw new NotImplementedException();
        }

        public Type GetDataContractType(Type type)
        {
            return type;
        }

        public object GetDeserializedObject(object obj, Type targetType)
        {
            return obj;
        }

        public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
        {
        }

        public object GetObjectToSerialize(object obj, Type targetType)
        {
            return ReplaceLocalDateWithUTC(obj);
        }

        public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
        {
            throw new NotImplementedException();
        }

        public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit)
        {
            throw new NotImplementedException();
        }

        private object ReplaceLocalDateWithUTC(object obj)
        {
            if (obj == null) return null;
            Type objType = obj.GetType();
            foreach (var field in objType.GetFields())
            {
                if (field.FieldType == typeof(DateTime))
                {
                    DateTime fieldValue = (DateTime)field.GetValue(obj);
                    if (fieldValue.Kind != DateTimeKind.Utc)
                    {
                        field.SetValue(obj, fieldValue.ToUniversalTime());
                    }
                }
            }

            return obj;
        }
    }
    public static void Test()
    {
        MemoryStream ms = new MemoryStream();
        DataContractJsonSerializer dcjs = new DataContractJsonSerializer(typeof(MyType), null, int.MaxValue, true, new MySurrogate(), false);
        MyType t = new MyType
        {
            d1 = new MyTypeWithDates { Start = DateTime.Now, End = DateTime.Now.AddMinutes(1) },
            d2 = new MyTypeWithDates { Start = DateTime.Now.AddHours(1), End = DateTime.Now.AddHours(2) },
        };
        dcjs.WriteObject(ms, t);
        Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
    }
}