Сериализация времени UTC c#
у меня есть datetime datamember в datacontract. По умолчанию datacontractserializer сериализует время UTC до . Мне это нужно в yyyy-MM-ddTHH:mm:ss.000Z
формат, но не имеют контроля над datacontracts. Так что я могу сделать с DataContractSerializer, который дал бы мне время UTC в формате, который я хочу. Спасибо
1 ответов
Я создал реализацию, которая использует реализацию IDataContractSurrogate для сериализации ваших DTO с DTO, которыми вы владеете.
ДТО это
вы не предоставили DTO, поэтому я создал один, чтобы быть вашим оригинальным DTO (который вы не можете изменить) и одной заменой DTO, которой мы владеем. Они будут иметь одинаковую общедоступную подпись, за исключением того, что их свойства DateTime изменяются на строковые типы.
/// <summary>
/// original DTO, is fixed
/// </summary>
[DataContract]
class DTO
{
[DataMember]
public DateTime FirstDate { get; set; }
}
/// <summary>
/// Our own DTO, will act as surrogate
/// </summary>
[DataContract(Name="DTO")]
class DTO_UTC
{
[DataMember]
public string FirstDate { get; set; }
}
IDataContractSurrogate
В IDataContractSurrogate предоставляет методы, необходимые для замены одного типа на другой во время сериализации и десериализации.
Я вот просто отражение. Если вам нужна лучшая производительность, посмотрите на эмиссию сгенерированного кода между типами или даже создайте целевые типы.
public class DTOTypeSurrogate : IDataContractSurrogate
{
// this determines how you want to replace one type with the other
public Type GetDataContractType(Type type)
{
if (type == typeof(DTO))
{
return typeof(DTO_UTC);
}
return type;
}
public object GetDeserializedObject(object obj, Type targetType)
{
// do we know this type
if (targetType == typeof(DTO))
{
// find each DateTime prop and copy over
var objType = obj.GetType();
var target = Activator.CreateInstance(targetType);
foreach(var prop in targetType.GetProperties())
{
// value comes in
var src = objType.GetProperty(prop.Name);
// do we need special handling
if (prop.PropertyType == typeof(DateTime))
{
DateTime utcConvert;
// parse to a datetime
if (DateTime.TryParse(
(string) src.GetValue(obj),
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.AdjustToUniversal,
out utcConvert))
{
// store
prop.SetValue(target, utcConvert);
}
}
else
{
// store non DateTime types
prop.SetValue(target, src);
}
}
return target;
}
return obj;
}
public object GetObjectToSerialize(object obj, Type targetType)
{
// go from DTO to DTO_UTC
if (targetType == typeof(DTO_UTC))
{
var utcObj = Activator.CreateInstance(targetType);
var objType = obj.GetType();
// find our DateTime props
foreach(var prop in objType.GetProperties())
{
var src = prop.GetValue(obj);
if (prop.PropertyType == typeof(DateTime))
{
// create the string
var dateUtc = (DateTime)src;
var utcString = dateUtc.ToString(
"yyyy-MM-ddThh:mm:ss.000Z",
System.Globalization.CultureInfo.InvariantCulture);
// store
targetType.GetProperty(prop.Name).SetValue(utcObj, utcString);
} else
{
// normal copy
targetType.GetProperty(prop.Name).SetValue(utcObj, src);
}
}
return utcObj;
}
// unknown types return the original obj
return obj;
}
// omitted the other methods in the interfaces for brevity
}
использование сериализатора
здесь мы создаем DataContractSerializer и предоставляем ему экземпляр DTO, а после сериализации мы обращаемся процесс, чтобы проверить, если результат тот же.
var surrogateSerializer =
new DataContractSerializer(
typeof(DTO),
new Type[] {},
Int16.MaxValue,
false,
true,
new DTOTypeSurrogate()); // here we provide our own implementation
var ms = new MemoryStream();
// test data
var testDto = new DTO {
FirstDate = new DateTime(2015, 12, 31, 4, 5, 6, DateTimeKind.Utc) };
// serialize
surrogateSerializer.WriteObject(ms, testDto);
// debug
var wireformat = Encoding.UTF8.GetString(ms.ToArray());
//reset
ms.Position = 0;
//deserialize
var dtoInstance = (DTO) surrogateSerializer.ReadObject(ms);
// verify we have the same data returned
Debug.Assert(dtoInstance.FirstDate == testDto.FirstDate);