2017-09-21 5 views
0

私の質問はthis oneと非常によく似ていますが、元の回答にコメントを投稿するには十分な評判がありません。DateTimeの列型は、カスタムクラスのDataTableプロパティをデシリアライズした後にString型になります

FillPDFというカスタムクラスがあります。これは、サーバーでシリアル化してクライアントでデシリアライズしています。

FillPDF dsPDF = JsonConvert.DeserializeObject<FillPDF>(json); 

FillPDFクラスは、私がDateTimeタイプが不適切Stringとして設定されている理由を知ってる元の質問に対する解決策を読んでからDataTables

のコレクションが含まれてDataSetプロパティで構成されています。私はJson.NetのDataTableConverterがそれぞれDataColumn.DataTypeを最初の行だけを見て推測していることを理解しています(私の最初の行にはNULLの値があります)。

元の質問から解決策を実装しようとしました。 DbcはDataTableConverterをオーバーライドすることを提案しました。私はそのようにやったと私はそうのようにシリアライズとデシリアライズ時にsettingsオブジェクトを使用しています:

// Server 
FillPDF pdfData = new FillPDF(strUniqueColID);      
var settings = new JsonSerializerSettings { Converters = new[] { new TypeInferringDataTableConverter() } }; 
string json = JsonConvert.SerializeObject(pdfData, Formatting.Indented,settings); 


// Client 
var settings = new JsonSerializerSettings { Converters = new[] { new TypeInferringDataTableConverter() } }; 
FillPDF dsPDF = JsonConvert.DeserializeObject<FillPDF>(json,settings); 

は、しかし、私はすべてのエラーを得ていないことだし、私の基礎となるのDataTableが正常に直列化復元されていません。これは、私が元の質問のように単純にDataTableとは対照的にカスタムオブジェクトをシリアライズ/デシリアライズしているためです。私が行うことができるようにしたいと思い何

は次のとおりです。

if(c.ColumnName.toLower().Contains("date")) 
{ 
    // Set Column's Type to DateTime because I know all Column Names containing "date" should be of type DateTime 
} 

おそらくこれがオーバーライドさTypeInferringDataTableConverterに追加する必要があります。

私はここからどこに行くべきかわからないので、私は助けを必要としています。

ありがとう、

ジャスティン。

+1

問題は、['DataSetConverter'](https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Converters/DataSetConverter.cs#L89)のNewtonsoftのハードコードを使用しているようです'DataTableConverter converter = new DataTableConverter();'を実行して、 'DataTableConverter'を呼び出します。 'DataSetConverter'の独自のバージョンを作成する必要があるかもしれません。 – dbc

+0

迅速な対応をありがとう! '' DataSetConverter''をオーバーライドしてみましょう – JEllery

答えて

1

問題DataTableConverter converter = new DataTableConverter();をやった後、直接そのReadJson()メソッドを呼び出すことにより、NewtonsoftのDataTableConverterを使用して、そのNewtonsoftのDataSetConverterハードコードのようです。したがって、あなたのコンバータは決して使用されません。

public class DataSetConverter<TDataTableConverter> : DataSetConverter where TDataTableConverter : JsonConverter, new() 
{ 
    // This code adapted from 
    // https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Converters/DataSetConverter.cs 
    // Copyright (c) 2007 James Newton-King 
    // Licensed under The MIT License (MIT): 
    // https://github.com/JamesNK/Newtonsoft.Json/blob/master/LICENSE.md 

    readonly TDataTableConverter converter = new TDataTableConverter(); 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.Null) 
     { 
      return null; 
     } 

     // handle typed datasets 
     DataSet ds = (objectType == typeof(DataSet)) 
      ? new DataSet() 
      : (DataSet)Activator.CreateInstance(objectType); 

     reader.ReadAndAssert(); 

     while (reader.TokenType == JsonToken.PropertyName) 
     { 
      DataTable dt = ds.Tables[(string)reader.Value]; 
      bool exists = (dt != null); 

      dt = (DataTable)converter.ReadJson(reader, typeof(DataTable), dt, serializer); 

      if (!exists) 
      { 
       ds.Tables.Add(dt); 
      } 

      reader.ReadAndAssert(); 
     } 

     return ds; 
    } 
} 

public static class JsonReaderExtensions 
{ 
    public static void ReadAndAssert(this JsonReader reader) 
    { 
     if (reader == null) 
      throw new ArgumentNullException(); 
     if (!reader.Read()) 
     { 
      new JsonReaderException(string.Format("Unexpected end at path {0}", reader.Path)); 
     } 
    } 
} 

その後コンバーターのリストにDataSetConverter<TypeInferringDataTableConverter>を追加:ジェームズ・ニュートン・キングのoriginal codeを適応させることによって、同様DataSetConverterの独自のバージョンを作成することです

一つの解決策。ちなみに

、あなたがする必要があるすべては、列名が文字列"date"が含まれている場合、あなたはdeserialize a datatable with a missing first columnから、コンバータの線に沿ってTypeInferringDataTableConverterよりも単純なコンバータを作成することを検討可能性があるDateTimeに列タイプを設定する場合:

  • フォークコードDataTableConverter。最初にライセンスに注意してください:

    // Permission is hereby granted, free of charge, to any person 
    // obtaining a copy of this software and associated documentation 
    // files (the "Software"), to deal in the Software without 
    // restriction, including without limitation the rights to use, 
    // copy, modify, merge, publish, distribute, sublicense, and/or sell 
    // copies of the Software, and to permit persons to whom the 
    // Software is furnished to do so, subject to the following 
    // conditions: 
    // 
    // The above copyright notice and this permission notice shall be 
    // included in all copies or substantial portions of the Software. 
    // 
    // ... 
    
  • をごフォークコンバータサブクラスNewtonsoftのDataTableConverterを持っています。 WriteJson()のコードをすべて削除してください。次に、行152の周り列名を渡すGetColumnDataType()の呼び出しを修正

    private static Type GetColumnDataType(JsonReader reader, string columnName) 
    { 
        JsonToken tokenType = reader.TokenType; 
    
        switch (tokenType) 
        { 
         case JsonToken.String: 
          if (columnName.IndexOf("date", StringComparison.OrdinalIgnoreCase) >= 0) 
           return typeof(DateTime); 
          return reader.ValueType; 
    
         case JsonToken.Integer: 
         case JsonToken.Boolean: 
         case JsonToken.Float: 
         case JsonToken.Date: 
         case JsonToken.Bytes: 
          return reader.ValueType; 
    
         case JsonToken.Null: 
         case JsonToken.Undefined: 
          if (columnName.IndexOf("date", StringComparison.OrdinalIgnoreCase) >= 0) 
           return typeof(DateTime); 
          return typeof(string); 
    
         case JsonToken.StartArray: 
          reader.ReadAndAssert(); 
          if (reader.TokenType == JsonToken.StartObject) 
          { 
           return typeof(DataTable); // nested datatable 
          } 
    
          Type arrayType = GetColumnDataType(reader, columnName); 
          return arrayType.MakeArrayType(); 
         default: 
          throw JsonSerializationException.Create(reader, "Unexpected JSON token when reading DataTable: {0}".FormatWith(CultureInfo.InvariantCulture, tokenType)); 
        } 
    } 
    
  • Type columnType = GetColumnDataType(reader, columnName); 
    
  • は、列名を渡し、必要なロジックを追加するGetColumnDataType()を変更します

    などのスタティックな拡張メソッドを持つ内部メソッドがない場合は、スタブはhereとなります。

タイプstringの列をDataSet内のすべてのテーブルのすべての列をループに、コンテナクラスの[OnDeserialized]場合に、あろうNewtonsoftのコンバータの独自のバージョンを作成し、変換に代替溶液(またはobject)には、How To Change DataType of a DataColumn in a DataTable?の回答のいずれかを使用して、"date"DateTimeの列が含まれています。

+1

あなたの助けてくれてありがとう! TypeInferringDataTableConverterを使用する独自のカスタムDataSetConverterを実装していますが、うまく機能しているようです。もう一度、昨日の迅速な対応とあなたが提供したすべてのおかげで、ありがとう! – JEllery

関連する問題