当前位置:  开发笔记 > 编程语言 > 正文

DataContractJsonSerializer和Enums

如何解决《DataContractJsonSerializer和Enums》经验,为你挑选了3个好方法。



1> Darin Dimitr..:

看起来这是设计的,这种行为无法改变:

枚举成员值在JSON中被视为数字,这与在数据协定中处理它们的方式不同,它们作为成员名称包含在内.

这是一个使用替代(以及更好和更可扩展的IMO)序列化器的示例,它可以实现您的目标:

using System;
using Newtonsoft.Json;

class Program
{
    static void Main(string[] args)
    {
        var baz = Foo.Baz;
        var serializer = new JsonSerializer();
        serializer.Converters.Add(new JsonEnumTypeConverter());
        serializer.Serialize(Console.Out, baz);
        Console.WriteLine();
    }
}

enum Foo
{
    Bar,
    Baz
}

public class JsonEnumTypeConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Foo);
    }
    public override void WriteJson(JsonWriter writer, object value)
    {
        writer.WriteValue(((Foo)value).ToString());
    }

    public override object ReadJson(JsonReader reader, Type objectType)
    {
        return Enum.Parse(typeof(Foo), reader.Value.ToString());
    }
}


我相信这样做的新方法是`jsonSerializer.Converters.Add(new StringEnumConverter()); ` - 截至4.5

2> Jason Robert..:

为了得到2路串行/ deserilization WCF的JSON你可以添加一个字符串类型的第二获取设置属性,当你在建设你的javascript JSON对象使用字符串命名属性,在服务器端使用强类型枚举的版本:如

public class DTOSearchCriteria
{
    public int? ManufacturerID { get; set; }
    public int? ModelID { get; set; }


    private SortBy _sort;


    public SortBy SortType
    {
        get
        {
            return _sort;
        }
        set
        {
            _sort = value;
        }
    }

    public String Sort 
    {
        get
        {
            return _sort.ToString();
        }
        set
        {
            _sort = (SortBy) Enum.Parse(typeof(SortBy), value);
        }
    }





    public int PageSize { get; set; }
    public int PageNumber { get; set; }
}


public enum SortBy
{
    PriceDescending,
    PriceAscending
}



3> 小智..:

我疯狂地试图找到这个问题的优雅解决方案,因为似乎每个人都默认使用Newtonsoft的序列化程序来解决这个问题.尽管Newtonsoft提供了更多功能,但它确实存在一些严重缺陷.要列举几个:为参数构造函数,疯狂行为的需要,如果你想序列化实现IEnumerable的类,它执行时使用抽象类型非常糟糕(因为它不利用KnownTypes属性,和解决方法生成将您的内部命名空间公开给调用者的详细输出.

另一方面,在MVC4 WebApi解决方案上使用DataContractJsonSerializer时,几乎没有关于如何自定义DataContractJsonSerializer的示例.

我花了一段时间才找到一个表示枚举为字符串的解决方案,并解决了DataContractJsonSerializer附带的已知DateTime格式问题.

第一部分 - 将这些扩展方法放在扩展类中~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~

#region JSon

    /// Serializes an object to JSon.
    /// The object to serialize.
    /// Returns a byte array with the serialized object.
    /// This implementation outputs dates in the correct format and enums as string.
    [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "Reviewed.")]
    public static byte[] SerializeJson(this object obj)
    {
        using (MemoryStream b = new MemoryStream())
        {
            SerializeJson(obj, b);
            return b.ToArray();
        }
    }

    /// Serializes an object to JSon.
    /// The object to serialize.
    /// The stream to write to.
    /// This implementation outputs dates in the correct format and enums as string.
    [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "Reviewed.")]
    public static void SerializeJson(this object obj, Stream stream)
    {
        var settings = new DataContractJsonSerializerSettings();
        settings.DateTimeFormat = new System.Runtime.Serialization.DateTimeFormat("yyyy-MM-dd'T'HH:mm:ssZ");
        settings.DataContractSurrogate = new EnumToStringDataContractSurrogate();

        var type = obj == null ? typeof(object) : obj.GetType();

        var enumerationValue = obj as System.Collections.IEnumerable;

        var fixedValue = enumerationValue != null
                         ? type.IsGenericType && !type.GetGenericArguments()[0].IsInterface
                            ? enumerationValue.ToArray(type.GetGenericArguments()[0])
                            : enumerationValue.OfType().ToArray()
                         : obj;

        if (enumerationValue != null && (!type.IsGenericType || (type.IsGenericType || type.GetGenericArguments()[0].IsInterface)))
        {
            var firstMember = (fixedValue as System.Collections.IEnumerable).OfType().FirstOrDefault();
            if (firstMember != null)
                fixedValue = enumerationValue.ToArray(firstMember.GetType());
        }

        var fixedType = obj == null
                        ? type
                        : fixedValue.GetType();

        var jsonSer = new DataContractJsonSerializer(fixedType, settings);
        jsonSer.WriteObject(stream, fixedValue);
    }

    /// 
    /// Deserializes an object.
    /// 
    /// The output type of the object.
    /// The serialized contents.
    /// Returns the typed deserialized object.
    /// This implementation outputs dates in the correct format and enums as string.
    [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "JSon")]
    [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "Reviewed.")]
    public static T DeserializeJSon(this byte[] data)
    {
        using (MemoryStream b = new MemoryStream(data))
            return DeserializeJSon(b);
    }

    /// Deserializes a JSon object.
    /// The output type of the object.
    /// The stream to read from.
    /// Returns the typed object.
    /// This implementation outputs dates in the correct format and enums as string.
    [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "JSon")]
    [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "Reviewed.")]
    public static T DeserializeJSon(this Stream stream)
    {
        var settings = new DataContractJsonSerializerSettings();
        settings.DateTimeFormat = new System.Runtime.Serialization.DateTimeFormat("yyyy-MM-dd'T'HH:mm:ssZ");
        settings.DataContractSurrogate = new EnumToStringDataContractSurrogate();

        var jsonSer = new DataContractJsonSerializer(typeof(T), settings);
        return (T)jsonSer.ReadObject(stream);
    }

    /// Deserializes a JSon object.
    /// The serialized contents.
    /// The target type.
    /// Returns the typed deserialized object.
    /// This implementation outputs dates in the correct format and enums as string.
    [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "JSon")]
    [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "Reviewed.")]
    public static object DeserializeJSon(this byte[] data, Type targetType)
    {
        using (MemoryStream b = new MemoryStream(data))
        {
            return DeserializeJSon(b, targetType);
        }
    }

    /// Deserializes a JSon object.
    /// The serialized contents.
    /// The target type.
    /// Returns the typed deserialized object.
    /// This implementation outputs dates in the correct format and enums as string.
    [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "JSon")]
    [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "Reviewed.")]
    public static object DeserializeJSon(this Stream data, Type targetType)
    {
        var settings = new DataContractJsonSerializerSettings();
        settings.DateTimeFormat = new System.Runtime.Serialization.DateTimeFormat("yyyy-MM-dd'T'HH:mm:ssZ");
        settings.DataContractSurrogate = new EnumToStringDataContractSurrogate();

        var jsonSer = new DataContractJsonSerializer(targetType, settings);
        return jsonSer.ReadObject(data);            
    }

    /// Enumerator contract surrogate.
    internal class EnumToStringDataContractSurrogate : IDataContractSurrogate
    {
        Type IDataContractSurrogate.GetDataContractType(Type type)
        {
            return type == typeof(Enum) ? typeof(string) : type;
        }

        object IDataContractSurrogate.GetDeserializedObject(object obj, Type targetType)
        {
            if (targetType.IsEnum)
            {
                return obj == null
                       ? System.Enum.GetValues(targetType).OfType().FirstOrDefault()
                       : System.Enum.Parse(targetType, obj.ToString());
            }
            return obj;
        }

        object IDataContractSurrogate.GetObjectToSerialize(object obj, Type targetType)
        {
            if (obj is Enum)
            {
                var pair = Enum.GetName(obj.GetType(), obj);
                return pair;
            }

            return obj;
        }

        object IDataContractSurrogate.GetCustomDataToExport(Type clrType, Type dataContractType)
        {
            throw new NotImplementedException();
        }

        object IDataContractSurrogate.GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType)
        {
            throw new NotImplementedException();
        }

        void IDataContractSurrogate.GetKnownCustomDataTypes(System.Collections.ObjectModel.Collection customDataTypes)
        {
            throw new NotImplementedException();
        }

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

        System.CodeDom.CodeTypeDeclaration IDataContractSurrogate.ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
        {
            throw new NotImplementedException();
        }
    }

    #endregion


    /// Creates an array from a non generic source.
    /// The source.
    /// The target type of the array.
    /// Returns a typed array.
    public static Array ToArray(this IEnumerable source, Type type)
    {
        var param = Expression.Parameter(typeof(IEnumerable), "source");
        var cast = Expression.Call(typeof(Enumerable), "Cast", new[] { type }, param);
        var toArray = Expression.Call(typeof(Enumerable), "ToArray", new[] { type }, cast);
        var lambda = Expression.Lambda>(toArray, param).Compile();

        return lambda(source);
    }


第二部分 - 通过封装DataContractJsonSerializer创建自己的格式化~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/// Custom implementation of DataContract formatter.
public class DataContractJsonFormatter : MediaTypeFormatter
{

    /// Creates a new instance.
    public DataContractJsonFormatter()
    {
        SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
    }

    /// Gets if the formatter the write a given type.
    /// The type to handle.
    /// Returns if the formatter the write a given type.
    public override bool CanWriteType(Type type)
    {
        return true;
    }

    /// Gets if the formatter the read a given type.
    /// The type to handle.
    /// Returns if the formatter the read a given type.
    public override bool CanReadType(Type type)
    {
        return true;
    }

    /// Deserializes an object.
    /// The target type.
    /// The stream to read from.
    /// The http content.
    /// A logger.
    /// Returns the deserialized object.
    public override Task ReadFromStreamAsync(Type type, Stream readStream, System.Net.Http.HttpContent content, IFormatterLogger formatterLogger)
    {
        var task = Task.Factory.StartNew(() =>
        {
            return readStream.DeserializeJSon(type);
        });

        return task;
    }

    /// Serializes an object.
    /// The target type.
    /// The object to serialize.
    /// The stream to write to.
    /// The http content.
    /// The context.
    /// Returns the deserialized object.
    public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, System.Net.Http.HttpContent content, System.Net.TransportContext transportContext)
    {
        var task = Task.Factory.StartNew(() =>
        {
            value.SerializeJson(writeStream);
        });

        return task;
    }
}


第三部分 - 编辑你的Global.asax文件并使用你的新JSon格式化程序~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    /// Event handlers of when the application starts.
    [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
    protected void Application_Start()
    {
       //Register my custom DataContract JSon serializer
        GlobalConfiguration.Configuration.Formatters.Insert(0, new DataContractJsonFormatter());

        //Register areas
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
       // BundleConfig.RegisterBundles(BundleTable.Bundles);

        //JSON serialization config
        var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
        json.UseDataContractJsonSerializer = false;
    }

推荐阅读
爱唱歌的郭少文_
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有