2017-01-21 7 views
1

以下のC#オブジェクトに対してJSONを明示的に使用しないか、ASP.NET Web APIのモデルバインドメカニズムを使用して、idの値が自動的にintに変換されます。私は例外がスローされるか、型の不一致があるのでエラーを発生させることが期待されます。これはJSONが仕様で動作する方法ですか?そうでない場合は、どうすればこのような自動変換を防ぐことができますか?JSON逆シリアル化 - 文字列が自動的にIntに変換されます

JSON:{"id":"4", "name":"a"} C#のモデル:int id; string name

+0

これは、NewtonSoftなどのJSONシリアル化フレームワークによって提供される機能です。 JSONオブジェクトでは、everytingは文字列です。型変換を行うフレームワークです。 jsonの文字列に "id": "somestring"が含まれていると、間違いなくエラーが発生します。フレームワークは、JSON文字列値がターゲットタイプの形式である限り、型変換を実行しようとします。 –

+1

"JSONオブジェクトでは、everytingは文字列です" ... ...うん?いいえ{"a":4}と{"a": "4"}は異なります。 "a"は1つのJSON番号ともう1つの文字列です。 JSONオブジェクトでは、すべてが文字列ではありません。プロパティは、文字列、数字、その他の文字、または配列です。 JSON型は非常に基本的なものなので、JSON配列を使用している場合は、それは問題ありません(JSON型は非常に基本的なので、数字として解析することができ、逆シリアル化された型は数値です)。 – Triynko

答えて

0

は、それはあなたが最終的に欲しいものである場合は単なる文字列あなたのC#のモデルを作ってみましょう。

0

yuoが明示的に

public class Model 
{ 
    public string id { get; set; } 
    public string name { get; set; } 
} 

モデルクラスを定義し、それをデシリアライズした場合:

var res = JsonConvert.DeserializeObject<Model>(text); 

あなたはidとしてstrign取得します。

var t = "{ \"id\":\"4\", \"name\" : \"a\"}"; 
dynamic res = JsonConvert.DeserializeObject(t); 
var i = res.id; 
var type = i.Type; 

と後の私のタイプはString

それはあなたのJSONにstrignていますので、それは本当であること:

は実際に私がテストをした、あなたの例が間違っている、と思います。あなたは定義でき整数のとおりです。

var t = "{ \"id\":4, \"name\" : \"a\"}"; 

そして、それは整数としてデシリアライズされることafetr(私の例ではタイプとして整数を参照されます)。ほとんどの人々は行動のこの種をしたいので、あなたが記述何

0

は、機能です。私がチェックしていないが、私はそれが自動的にのプロパティタイプをターゲットに、文字列から変換しようとしConvert.ChangeType(strValue, propertyType);のようなものを使用しています賭けます。

あなただけの文字列としてそれを必要とする場合は、マクシムのソリューションを使用します。

また、必要に応じて、両方のタイプを持っているために余分なプロパティを組み込むことができますあなたのモデル:プリミティブ型をデシリアライズするとき、それはプリミティブJSON値を変換します:これはJson.NETの機能がある

public class Model 
{ 
    public int id { get; set; } 
    public string idStr => id.ToString(); 

    public string name { get; set; } 
} 
+0

タイプが正確に一致しないときにエラーが発生するようにデシリアライザを設定することはできますか?その逆もあります(たとえば、ターゲットタイプの場合はリストとしてデシリアライズします)。 –

+0

期待される型を持たない 'id'を検出しますか?はいの場合は、動的(Maksimの解決策をチェックする)として逆直列化し、型をチェックします。' JsonConvert.DeserializeObject(jsonStr).id.Type' – Alexei

4

可能な限りターゲットc#型文字列"4"は整数に変換できるため、逆シリアル化は成功します。コンバータのような値を受け入れる

public class StrictIntConverter : JsonConverter 
{ 
    readonly JsonSerializer defaultSerializer = new JsonSerializer(); 

    public override bool CanConvert(Type objectType) 
    { 
     return objectType.IsIntegerType(); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     switch (reader.TokenType) 
     { 
      case JsonToken.Integer: 
      case JsonToken.Float: // Accepts numbers like 4.00 
      case JsonToken.Null: 
       return defaultSerializer.Deserialize(reader, objectType); 
      default: 
       throw new JsonSerializationException(string.Format("Token \"{0}\" of type {1} was not a JSON integer", reader.Value, reader.TokenType)); 
     } 
    } 

    public override bool CanWrite { get { return false; } } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 

public static class JsonExtensions 
{ 
    public static bool IsIntegerType(this Type type) 
    { 
     type = Nullable.GetUnderlyingType(type) ?? type; 
     if (type == typeof(long) 
      || type == typeof(ulong) 
      || type == typeof(int) 
      || type == typeof(uint) 
      || type == typeof(short) 
      || type == typeof(ushort) 
      || type == typeof(byte) 
      || type == typeof(sbyte) 
      || type == typeof(System.Numerics.BigInteger)) 
      return true; 
     return false; 
    }   
} 

注:この機能を使用しない場合は、読み込まれるトークンが実際に数値(またはnull、NULL可能値のため)であることをチェックする整数型のためcustom JsonConverterを作成することができます整数として4.00JsonToken.Floatのチェックを削除して変更することができます。

public class RootObject 
{ 
    [JsonConverter(typeof(StrictIntConverter))] 
    public int id { get; set; } 

    public string name { get; set; } 
} 

を、またはすべての不可欠な分野に適用するJsonSerializerSettingsでコンバータが含まれています:

あなたは次のように直接あなたのモデルに適用することができます

var settings = new JsonSerializerSettings 
{ 
    Converters = { new StrictIntConverter() }, 
}; 
var root = JsonConvert.DeserializeObject<RootObject>(json, settings); 
最後に

は、JSONシリアライザの設定を適用しますWeb APIではグローバルに、たとえばhereを参照してください。

関連する問題