Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
203 views
in Technique[技术] by (71.8m points)

c# - How to serialize ANY object into a string?

I'm running into an issue where my JSON serializer is failing randomly due to the character < showing up from time to time. I can't nail down where this is coming from and I want to - on exception - reserialize using a different method so I can see a full representation of the offending object. Is there any way to do this?

My current code:

// data is of type 'object'
serialized = JsonConvert.SerializeObject(data, new JsonSerializerSettings() {
    Error = delegate(object sender, ErrorEventArgs args) {
        // reserialize here and output object so I know what the heck is going on
    }
})
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There is no foolproof way to serialize any and every possible c# object.

Instead, you have a few ways to attack your problem:

  1. Turn on Json.NET tracing. See Debugging with Serialization Tracing. This should tell you where in your object graph the problem is occurring.

  2. Rather than serializing with JsonConvert.SerializeObject(), if you serialize with JsonSerializer.Serialize() and write to a string using a JsonTextWriter wrapping a StringWriter, you can flush the writer and log the partial serialization. That may give some idea where the problem arises.

  3. You can try serializing using various other serializers, and if any work, log the result.

  4. If one of your object properties is throwing an exception, you might try to force serialization of fields instead. See JSON.Net: Force serialization of all private fields and all fields in sub-classes.

For instance, putting #1, #2 and #3 together gives the following method:

public static class JsonSerializerExtensions
{
    public static string SerializeObject(object obj, JsonSerializerSettings settings = null)
    {
        settings = settings ?? new JsonSerializerSettings();

        var sb = new StringBuilder();
        using (var writer = new StringWriter(sb))
        using (var jsonWriter = new JsonTextWriter(writer))
        {
            var oldError = settings.Error;
            var oldTraceWriter = settings.TraceWriter;
            var oldFormatting = settings.Formatting;
            try
            {
                settings.Formatting = Newtonsoft.Json.Formatting.Indented;
                if (settings.TraceWriter == null)
                    settings.TraceWriter = new MemoryTraceWriter();
                settings.Error = oldError + delegate(object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args)
                {
                    jsonWriter.Flush();

                    var logSb = new StringBuilder();
                    logSb.AppendLine("Serialization error: ");
                    logSb.Append("Path: ").Append(args.ErrorContext.Path).AppendLine();
                    logSb.Append("Member: ").Append(args.ErrorContext.Member).AppendLine();
                    logSb.Append("OriginalObject: ").Append(args.ErrorContext.OriginalObject).AppendLine();
                    logSb.AppendLine("Error: ").Append(args.ErrorContext.Error).AppendLine();
                    logSb.AppendLine("Partial serialization results: ").Append(sb).AppendLine();
                    logSb.AppendLine("TraceWriter contents: ").Append(settings.TraceWriter).AppendLine();

                    logSb.AppendLine("JavaScriptSerializer serialization: ");
                    try
                    {
                        logSb.AppendLine(new JavaScriptSerializer().Serialize(obj));
                    }
                    catch (Exception ex)
                    {
                        logSb.AppendLine("Failed, error: ").AppendLine(ex.ToString());
                    }

                    logSb.AppendLine("XmlSerializer serialization: ");
                    try
                    {
                        logSb.AppendLine(obj.GetXml());
                    }
                    catch (Exception ex)
                    {
                        logSb.AppendLine("Failed, error: ").AppendLine(ex.ToString());
                    }

                    logSb.AppendLine("BinaryFormatter serialization: ");
                    try
                    {
                        logSb.AppendLine(BinaryFormatterExtensions.ToBase64String(obj));
                    }
                    catch (Exception ex)
                    {
                        logSb.AppendLine("Failed, error: ").AppendLine(ex.ToString());
                    }

                    Debug.WriteLine(logSb);
                };
                var serializer = JsonSerializer.CreateDefault(settings);
                serializer.Serialize(jsonWriter, obj);
            }
            finally
            {
                settings.Error = oldError;
                settings.TraceWriter = oldTraceWriter;
                settings.Formatting = oldFormatting;
            }
        }

        return sb.ToString();
    }
}

public static class XmlSerializerExtensions
{
    public static T LoadFromXML<T>(this string xmlString)
    {
        using (StringReader reader = new StringReader(xmlString))
        {
            return (T)new XmlSerializer(typeof(T)).Deserialize(reader);
        }
    }

    public static string GetXml<T>(this T obj)
    {
        using (var textWriter = new StringWriter())
        {
            var settings = new XmlWriterSettings() { Indent = true, IndentChars = "  " };
            using (var xmlWriter = XmlWriter.Create(textWriter, settings))
                new XmlSerializer(obj.GetType()).Serialize(xmlWriter, obj);
            return textWriter.ToString();
        }
    }
}

public static class BinaryFormatterExtensions
{
    public static string ToBase64String<T>(T obj)
    {
        using (var stream = new MemoryStream())
        {
            new BinaryFormatter().Serialize(stream, obj);
            return Convert.ToBase64String(stream.GetBuffer(), 0, checked((int)stream.Length)); // Throw an exception on overflow.
        }
    }

    public static T FromBase64String<T>(string data)
    {
        return FromBase64String<T>(data, null);
    }

    public static T FromBase64String<T>(string data, BinaryFormatter formatter)
    {
        using (var stream = new MemoryStream(Convert.FromBase64String(data)))
        {
            formatter = (formatter ?? new BinaryFormatter());
            var obj = formatter.Deserialize(stream);
            if (obj is T)
                return (T)obj;
            return default(T);
        }
    }
}

You would likely replace the final Debug.WriteLine() with an appropriate logging method, then replace JsonConvert.SerializeObject(data) with JsonSerializerExtensions.SerializeObject(data) in your applications code.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...