将复杂类型序列化为简单类型JSON

时间:2013-06-05 19:52:28

标签: c# .net json serialization

我有一个复杂的类型,要序列化为字符串。我使用IXmlSerializable按需工作,现在我也尝试让它适用于JSON消息。目前我通过DataContractSerializer将其序列化为以下内容:

<MyXmlRootElement>_value's contents</MyXmlRootElement>

对于JSON输出,我想收到一个带有_value内容的JSON字符串。

此类型实现的内容多于下面描述的内容,还通过挂钩到我们的Web服务框架中的一些其他属性来影响生成的wsdl。所以生成的wsdl / xsd看起来都很棒,它只是没有给我所需的JSON。

[XmlRoot(ElementName = "MyXmlRootElement", Namespace = "MyNamespace"]
public class ComplexType : IXmlSerializable
{
    private string _value;
    public ComplexType(string value) { _value = value; }

    #region IXmlSerialiable Implementation

    public XmlSchema GetSchema() { return null; }

    public void ReadXml(XmlReader reader)
    {
        _value = reader.ReadString();
    }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteString(_value);
    }

    #endregion
}

我尝试实现ISerializable,这确实会影响生成的JSON,但它仍然将它放在一个复杂的(对象)类型中,即{ "ValueKey": "_value's contents" }。知道如何将它序列化为纯字符串,没有花括号吗?

2 个答案:

答案 0 :(得分:2)

解决方案比预期的要容易。您可以使用JsonConverter注册GlobalConfiguration。我在JsonConverter周围做了一个抽象包装,如下所示,其思路来自以下SO线程:How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects?

public abstract class CustomJsonConverter<T, TResult> : JsonConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // Load token from stream
        var token = JToken.Load(reader);

        // Create target object based on token
        var target = Create(objectType, token);

        var targetType = target.GetType();
        if (targetType.IsClass && targetType != typeof(string))
        {
            // Populate the object properties
            var tokenReader = token.CreateReader();
            CopySerializerSettings(serializer, tokenReader);
            serializer.Populate(token.CreateReader(), target);
        }

        return target;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        T typedValued = (T)value;
        TResult valueToSerialize = Convert(typedValued);

        serializer.Serialize(writer, valueToSerialize);
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof (T) == objectType;
    }

    protected virtual T Create(Type type, JObject jObject)
    {
        // reads the token as an object type
        if (typeof(TResult).IsClass && typeof(T) != typeof(string))
        {
            return Convert(token.ToObject<TResult>());
        }

        var simpleValue = jObject.Value<TResult>();
        return Convert(simpleValue);
    }

    protected abstract TResult Convert(T value);
    protected abstract T Convert(TResult value);

    private static void CopySerializerSettings(JsonSerializer serializer, JsonReader reader)
    {
        reader.Culture = serializer.Culture;
        reader.DateFormatString = serializer.DateFormatString;
        reader.DateTimeZoneHandling = serializer.DateTimeZoneHandling;
        reader.DateParseHandling = serializer.DateParseHandling;
        reader.FloatParseHandling = serializer.FloatParseHandling;
    }
}

然后,您可以使用此功能执行以下操作

public class DateTimeToStringJsonConverter : CustomJsonConverter<DateTime, string>
{
    protected override string Convert(DateTime value)
    {
        return value.ToString();
    }

    protected override DateTime Convert(string value)
    {
        return DateTime.Parse(value);
    }
}

然后最后在Global.asax.cs

中注册GlobalConfiguration的实例
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new DateTimeToStringJsonConverter());

任何想法/想法/意见?谢谢!


编辑:2018.10.16 - 由于来自原始SO answer的以下评论,更新了处理值类型作为源类型并复制序列化设置的代码:

  

注意:此解决方案遍布互联网,但有一个缺陷,在极少数情况下会出现。在ReadJson方法中创建的新JsonReader不会继承任何原始读者的配置值(Culture,DateParseHandling,DateTimeZoneHandling,FloatParseHandling等等)。在serializer.Populate()中使用新的JsonReader之前,应复制这些值。

答案 1 :(得分:1)

导入此命名空间System.Web.Script.Serialization;

string SerializeObject()
{
     var objs = new List<Test>()
     var objSerialized = new JavaScriptSerializer();
     return objSerialized .Serialize(objs);
}

我使用List作为示例,但您将使用您的对象。