C#でJSONデータをデシリアライズするまでにはまったこと

ダメだったパターン

以下のJSONデータをデシリアライズする。

[
  {
    "kind": 1,
    "id": "test",
    "pattern": "NORMAL",
    "timing": "FIRST",
    "value": "aiueo/kakikukeko",
    "comment": "hogehoge"
  },
  {
    "kind": 1,
    "id": "test2",
    "pattern": "NORMAL",
    "timing": "FIRST",
    "value": 3252,
    "comment": "hugahuga"
  }
]

使うモデルは以下

namespace HogeHoge
{
    [DataContract]
    public class DefaultValue
    {
        [DataMember(Name = "kind")]
        public string Kind { get; set; }

        [DataMember(Name = "id")]
        public string Id { get; set; }

        [DataMember(Name = "pattern")]
        public string Pattern { get; set; }

        [DataMember(Name = "timing")]
        public string Timing { get; set; }

        [DataMember(Name = "value")]
        public string Value { get; set; }

        [DataMember(Name = "comment")]
        public string Comment { get; set; }
    }
}

このデータを以下のような感じでデータ取得してJsonデータからデシリアライズしようとした。
.Net Core MVCでJsonデータをやり取りしているので、PhysicalFileProviderとか使ってる。
そこは今回のメインどころではないけど、どんなStringデータが来るか、予想できるように念のため掲載している。

    private static void Main(string[] args)
    {
        // Documents をルートディレクトリとして物理ファイルのプロバイダーを生成.
        using (
            PhysicalFileProvider provider =
            new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "StaticFiles")))
        {
            IFileInfo fileInfo = provider.GetFileInfo(@"test.json");
            Char[] buffer;
            using (var sr = new StreamReader(fileInfo.PhysicalPath))
            {
                buffer = new Char[(int)sr.BaseStream.Length];
                await sr.ReadAsync(buffer, 0, (int)sr.BaseStream.Length);
            }


            var jsonData = new String(buffer);
            var tmp = Deserialize<List<DefaultValue>>(jsonData);
        }
    }        

        /// <summary>
        /// Jsonメッセージをオブジェクトへデシリアライズします
        /// </summary>
        /// <param name="message"></param>
        /// <param name="enc"></param>
        /// <returns></returns>
        public static T Deserialize<T>(string message, Encoding enc)
        {
            using (var stream = new MemoryStream()
            {
                var serializer = new DataContractJsonSerializer(typeof(T));
                return (T)serializer.ReadObject(stream);
            }
        }

ここで、var tmp = Deserialize<List<DefaultValue>>(jsonData);の部分がうまくいかない。
こんなエラーがでる。

There was an error deserializing the object of type System.Collections.Generic.List`1[[WebSummary.Models.DefaultValue, WebSummary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]. Encountered unexpected character '

理由は、jsonDataの中に、エスケープしておくべき文字列が含まれているからだろう。

解決策

ただ、既にstringのオブジェクトになっているので、何をエスケープすべきなのか、どうやってエスケープするのかわからなかった。
色々ググって、以下の方法で解決することができた。

  1. Json.NETでワンクッションいれる。https://www.newtonsoft.com/json
  2. 今回は、Jsonのデータ形式的にjTokenで
  3. jToken.ToString(Formatting.None)でエスケープされた状態のstringを受け取る
var jsonData = new String(buffer);
var jToken = JToken.Parse(jsonData);
var tmp = WebSummaryUtil.Deserialize<List<DefaultValue>>(jToken.ToString(Formatting.None));

ところで、これってこういうもんなんだろうか。Jsonからクラスにデシリアライズ、もっとシンプルにできそうなのになぁ。。

C#C#

Posted by takumioda