Custom DataContractSerializer



我想在某些属性上忽略与datamember属性序列化对象。

说我有自定义属性myignoredAtamember。

我想要标记的属性对于我的自定义DataconTractSerializer是看不见的,但对于普通的datacontractserializer可见。

我必须使用datacontractserializer,而别无其他。

代码是Silverlight应用。

有人成功地完成了datacontractserializer的子分类?

对您的问题的答案很复杂,以下问题:

  1. DataContractSerializer已密封,因此无法群体检查以检查 MyIgnoreDataMember

  2. 使用序列化替代物在序列化过程中将适当的DTO注入您的对象图中,通常是要走的路 - 但是看起来它在Silverlight上不可用,请参阅此答案。

  3. DataContractSerializer不支持ShouldSerialize模式,如下所述,您不能仅通过回调方法抑制不希望的属性的序列化。

那么,您有什么选择?假设您的对象图看起来如下:

[DataContract(Name = "Root", Namespace = "http://www.MyNamespace.com")]
public class RootObject
{
    [DataMember]
    public NestedObject NestedObject { get; set; }
}
[DataContract(Name = "Nested", Namespace = "http://www.MyNamespace.com")]
public class NestedObject
{
    [DataMember]
    public string SensitiveData { get; set; }
    [DataMember]
    public string PublicData { get; set; }
}

您想有条件地抑制SensitiveData的输出。那么以下可能性是:

  1. 如果您只需要消除一些属性,则可以用EmitDefaultValue = false标记它们并在某些线程静态为true时返回默认值,例如:

    [DataContract(Name = "Root", Namespace = "http://www.MyNamespace.com")]
    public class RootObject
    {
        [DataMember]
        public NestedObject NestedObject { get; set; }
    }
    [DataContract(Name = "Nested", Namespace = "http://www.MyNamespace.com")]
    public class NestedObject
    {
        string sensitiveData;
        [DataMember(IsRequired = false, EmitDefaultValue = false)]
        public string SensitiveData
        {
            get
            {
                if (SerializationState.InCustomSerialization())
                    return null;
                return sensitiveData;
            }
            set
            {
                sensitiveData = value;
            }
        }
        [DataMember]
        public string PublicData { get; set; }
    }
    public static class SerializationState
    {
        [ThreadStatic]
        static bool inCustomSerialization;
        public static bool InCustomSerialization()
        {
            return inCustomSerialization;
        }
        public static IDisposable SetInCustomDeserialization(bool value)
        {
            return new PushValue<bool>(value, () => inCustomSerialization, b => inCustomSerialization = b);
        }
    }
    public struct PushValue<T> : IDisposable
    {
        Action<T> setValue;
        T oldValue;
        public PushValue(T value, Func<T> getValue, Action<T> setValue)
        {
            if (getValue == null || setValue == null)
                throw new ArgumentNullException();
            this.setValue = setValue;
            this.oldValue = getValue();
            setValue(value);
        }
        #region IDisposable Members
        // By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class.
        public void Dispose()
        {
            if (setValue != null)
                setValue(oldValue);
        }
        #endregion
    }
    

    然后,当序列化时,执行类似:

    using (SerializationState.SetInCustomDeserialization(true))
    {
        // Serialize with data contract serializer.
    }
    

    老实说。

  2. 您可以使用与真实类型相同的合同名称和名称空间制作整个DTO层次结构,并使用诸如AutoMapper之类的东西将真实类映射到DTO,并序列化DTOS:

    [DataContract(Name = "Root", Namespace = "http://www.MyNamespace.com")]
    class RootObjectDTO
    {
        [DataMember]
        public NestedObjectDTO NestedObject { get; set; }
    }
    [DataContract(Name = "Nested", Namespace = "http://www.MyNamespace.com")]
    class NestedObjectDTO
    {
        [DataMember]
        public string PublicData { get; set; }
    }
    

    如果在Silverlight上没有AutoMapper,则可以使用DataContractSerializer本身进行映射,因为合同名称和名称空间是相同的。IE。 - 将真实的根对象序列化到XML字符串(或XDocument,如下所示),将中间XML序列化到DTO root,然后序列化DTO。

  3. 您可以使用以下扩展类别序列化到内存中的XDocument(可在Silverlight中获得):

    public static partial class DataContractSerializerHelper
    {
        public static XDocument SerializeContractToXDocument<T>(this T obj)
        {
            return obj.SerializeContractToXDocument(null);
        }
        public static XDocument SerializeContractToXDocument<T>(this T obj, DataContractSerializer serializer)
        {
            var doc = new XDocument();
            using (var writer = doc.CreateWriter())
            {
                (serializer ?? new DataContractSerializer(obj.GetType())).WriteObject(writer, obj);
            }
            return doc;
        }
        public static T DeserializeContract<T>(this XDocument doc)
        {
            return doc.DeserializeContract<T>(null);
        }
        public static T DeserializeContract<T>(this XDocument doc, DataContractSerializer serializer)
        {
            if (doc == null)
                throw new ArgumentNullException();
            using (var reader = doc.CreateReader())
            {
                return (T)(serializer ?? new DataContractSerializer(typeof(T))).ReadObject(reader);
            }
        }
    }
    

    接下来,使用XPath查询修剪不希望的元素,然后将XDocument序列化为最终的XML表示。

  4. 最后,如果性能和内存使用优先级,则可以从此答案中使用ElementSkippingXmlTextWriter,以便将其写入修剪元素时。

相关内容

  • 没有找到相关文章

最新更新