DataContractJsonSerializerのJSON出力を改行・インデントする
先日の記事の補足です。
DataContractJsonSerializer
でJSONを生成すると、改行なしに1行になってしまいます。機械処理上はいいのですが、やはり人が見る場合もあるので、そこは考えてほしいところ。
ちょっと調べてみたら、実は簡単にできるんですね。
ここにコードがありました。
ポイントは、.NET4.5で追加された、JsonReaderWriterFactory.CreateJsonWriter(Stream, Encoding, Boolean, Boolean)
メソッド(および、String引数がさらに追加されたもの)です。
CreateJsonWriter
メソッド自体は以前からあったのですが、.NET4.5で引数にindent
が加わりました。そこで、これを指定して生成したXmlDictionaryWriter
を使えば、改行というかインデントされたJSONが得られます。
また、先ほどのSOの回答では、InvariantCulture
を指定することで、カルチャの影響(例えば小数点がピリオドかカンマか)も除去でき、安定した動作が期待できます。
SOの回答では、ファイル入出力が前提でしたが、JSONを文字列として処理するように書き換えてみました。
using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Runtime.Serialization.Json; using System.Threading; using System.Globalization; using System.Diagnostics; namespace JsonTestNET45 { public static class Json { private static readonly DataContractJsonSerializerSettings Settings = new DataContractJsonSerializerSettings { UseSimpleDictionaryFormat = true }; private static CultureInfo _cultureStorage = null; private static void PushCulture(CultureInfo culture) { if (_cultureStorage != null) throw new ApplicationException("PushCulture : double pushed!"); _cultureStorage = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = culture; } private static void PopCulture() { if (_cultureStorage == null) throw new ApplicationException("PopCulture : double popped!"); Thread.CurrentThread.CurrentCulture = _cultureStorage; _cultureStorage = null; } public static string ToJson<T>(this T data) { try { using (var stream = new MemoryStream()) { PushCulture(CultureInfo.InvariantCulture); try { using (var writer = JsonReaderWriterFactory.CreateJsonWriter( stream, Encoding.UTF8, true, true, " ")) { var serializer = new DataContractJsonSerializer(typeof(T), Settings); serializer.WriteObject(writer, data); writer.Flush(); var json = Encoding.UTF8.GetString(stream.ToArray()); return json; } } catch (Exception ex) { Debug.WriteLine("ObjectToJson Error (inner) : " + ex.ToString()); throw; } finally { PopCulture(); } } } catch (Exception ex) { Debug.WriteLine("ObjectToJson Error (outer) : " + ex.ToString()); throw; } } public static T JsonToObject<T>(this string json) { try { using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(json))) { PushCulture(CultureInfo.InvariantCulture); try { var serializer = new DataContractJsonSerializer(typeof(T), Settings); var item = (T)serializer.ReadObject(stream); return item; } catch (Exception ex) { Debug.WriteLine("OpenAsJson Error (inner) : " + ex.ToString()); throw; } finally { PopCulture(); } } } catch (Exception ex) { Debug.WriteLine("OpenAsJson Error (outer) : " + ex.ToString()); throw; } } } }
なお、これらを使う場合に型を外部から入力してそのまま使うと脆弱性につながりますのでご注意くださいませ。