2017-12-22 21 views
1

C#オブジェクトをJSONとしてストリームにシリアル化したいが、スキーマに従ってオブジェクトが有効でない場合はシリアル化を避ける。 JSON.NETとJson.NETスキーマを使用してこのタスクをどのように進めるべきですか?私が見るところでは、JSONスキーマに対してC#オブジェクトの検証を可能にするJSON.NETライブラリにはメソッドがありません。 C#オブジェクトをエンコードすることなく単に検証する直接的な方法はないというのは幾分奇妙なようです。この方法が利用できない理由が分かりますか?シリアル化の前にスキーマに対してオブジェクトを検証する

+0

あなたはこれを見ましたか? https://www.newtonsoft.com/json/help/html/JsonSchema.htm –

+1

[NullJsonWriter]を[自動的に作成されたオブジェクトへの参照](https://stackoverflow.com/a/30650904/3744182)から取得できます。 'JSchemaValidatingWriter'でラップし、[* Validate JSON with JSchemaValidatingWriter *](https://www.newtonsoft.com/jsonschema/help/html/JsonValidatingWriterAndSerializer.htm)に示すようにオブジェクトをテスト直列化してください。 – dbc

+0

@dbcそれをエンコードすることなくC#オブジェクトを検証する直接的な方法はないというのはやや奇妙なようです。この方法が利用できない理由が分かりますか? –

答えて

3

それは、このAPIは、現在利用可能ではないようです。推測すると、検証するJSON値を再帰的に生成するには、オブジェクトをシリアライズする作業の大部分が必要となるからです。それとも、Newtonsoftの誰もいないからかもしれない。ever designed, specified, implemented, tested, documented and shipped that feature

希望する場合は、SchemaExtensions classの一部として、file an enhancement requestがこのAPIをリクエストしている可能性があります。一方

、あなたは(例えばので、結果は非常に大きくなります)、あなたは、 Reference to automatically created objectsから NullJsonWriterをつかむ JSchemaValidatingWriter、テストでそれをラップすることができ、それを完全に直列化を発生させることなく、POCOをテスト・検証する必要がない場合 - Validate JSON with JSchemaValidatingWriterのようにオブジェクトをシリアル化します。 NullJsonWriterは実際には何も書き込まないため、完全なシリアル化( stringまたは JTokenのいずれか)を生成する際のパフォーマンスとメモリオーバーヘッドがなくなります。

まず、次の静的メソッドを追加:

// Example adapted from 
// https://www.newtonsoft.com/jsonschema/help/html/JsonValidatingWriterAndSerializer.htm 
// by James Newton-King 

string schemaJson = @"{ 
    'description': 'A person', 
    'type': 'object', 
    'properties': { 
    'name': {'type':'string'}, 
    'hobbies': { 
     'type': 'array', 
     'maxItems': 3, 
     'items': {'type':'string'} 
    } 
    } 
}";   
var schema = JSchema.Parse(schemaJson); 

var person = new 
{ 
    Name = "James", 
    Hobbies = new [] { ".Net", "Blogging", "Reading", "XBox", "LOLCATS" }, 
}; 

var settings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }; 
var isValid = JsonExtensions.TestValidate(person, schema, (o, a) => Console.WriteLine(a.Message), settings); 
// Prints Array item count 5 exceeds maximum count of 3. Path 'hobbies'. 

Console.WriteLine("isValid = {0}", isValid); 
// Prints isValid = False 

を経由してケースに気をつけてください:そして、同じように使用

public static class JsonExtensions 
{ 
    public static bool TestValidate<T>(T obj, JSchema schema, SchemaValidationEventHandler handler = null, JsonSerializerSettings settings = null) 
    { 
     using (var writer = new NullJsonWriter()) 
     using (var validatingWriter = new JSchemaValidatingWriter(writer) { Schema = schema }) 
     { 
      int count = 0; 
      if (handler != null) 
       validatingWriter.ValidationEventHandler += handler; 
      validatingWriter.ValidationEventHandler += (o, a) => count++; 
      JsonSerializer.CreateDefault(settings).Serialize(validatingWriter, obj); 
      return count == 0; 
     } 
    } 
} 

// Used to enable Json.NET to traverse an object hierarchy without actually writing any data. 
class NullJsonWriter : JsonWriter 
{ 
    public NullJsonWriter() 
     : base() 
    { 
    } 

    public override void Flush() 
    { 
     // Do nothing. 
    } 
} 

を。 Json.NETスキーマはcase sensitiveです。したがって、テスト検証の際に適切な契約リゾルバを使用する必要があります。

サンプルfiddle

0

あなたはJSON文字列から、あなたがオブジェクトと最初に比較するためのスキーマを必要とすることはできません。..

public void Validate() 
{ 
    //... 
    JsonSchema schema = JsonSchema.Parse("{'pattern':'lol'}"); 
    JToken stringToken = JToken.FromObject("pie"); 
    stringToken.Validate(schema); 
関連する問題