可以通过Newtonsoft.Json.Schema验证VALUES的Json Schema验证吗?

时间:2017-08-22 20:25:56

标签: c# json c#-4.0 json.net

我有一个小样本。如果我的Json好,它可以正常工作。如果我更改"标签" (也就是属性名称),它通过无效消息正常工作。如果我将Guid的值更改为非guid值,则Json Schema Validation不会失败。

有没有办法让Guid值验证失败?

public class MyCoolObject
{
    public Guid TheUuid { get; set; }

    public Int32 TheInteger { get; set; }

    public DateTime TheDateTime { get; set; }
}

和我的测试方法。当i = 2时(我将字符串设置为包含" NOTAGUID-3333-3333-3333-333333333333"),那就是我没有得到像我想要的错误消息到。

    private static void RunJsonSchemaValidate()
    {

        /* Note, the TheUuid is of type "string" and format "guid" */
        string jsonSchemaText = @"
                {
                  ""typeName"": ""MyCoolObject"",
                  ""additionalProperties"": false,
                  ""type"": ""object"",
                  ""required"": [
                    ""TheUuid"",
                    ""TheInteger"",
                    ""TheDateTime""
                  ],
                  ""properties"": {
                    ""TheUuid"": {
                      ""type"": ""string"",
                      ""format"": ""guid""
                    },
                    ""TheInteger"": {
                      ""type"": ""integer""
                    },
                    ""TheDateTime"": {
                      ""type"": ""string"",
                      ""format"": ""date-time""
                    }
                  },
                  ""$schema"": ""http://json-schema.org/draft-04/schema#""
                }
        ";

        Newtonsoft.Json.Schema.JSchema jschem = Newtonsoft.Json.Schema.JSchema.Parse(jsonSchemaText);

        for (int i = 0; i < 3; i++)
        {

            string jsonContent = string.Empty;

            switch (i)
            {
                case 1:
                    /* bad json, change the property NAME */
                    jsonContent = @"{
                        ""TheUuidXXX"": ""33333333-3333-3333-3333-333333333333"",
                        ""TheInteger"": 2147483647,
                        ""TheDateTime"": ""2017-08-22T15:32:10.7023008-04:00""
                    }";
                    break;
                case 2:
                    /* bad json, change the property VALUE */
                    jsonContent = @"{
                        ""TheUuid"": ""NOTAGUID-3333-3333-3333-333333333333"",
                        ""TheInteger"": 2147483647,
                        ""TheDateTime"": ""2017-08-22T15:32:10.7023008-04:00""
                    }";
                    break;
                case 3:
                    /* bad json, bad integer */
                    jsonContent = @"{
                        ""TheUuid"": ""33333333-3333-3333-3333-333333333333"",
                        ""TheInteger"": notAnumber,
                        ""TheDateTime"": ""2017-08-22T15:32:10.7023008-04:00""
                    }";
                    break;
                case 4:
                    /* bad json, bad date */
                    jsonContent = @"{
                        ""TheUuid"": ""33333333-3333-3333-3333-333333333333"",
                        ""TheInteger"": 2147483647,
                        ""TheDateTime"": ""NOTADATE""
                    }";
                    break;
                default:
                    /* good json */
                    jsonContent = @"{
                        ""TheUuid"": ""33333333-3333-3333-3333-333333333333"",
                        ""TheInteger"": 2147483647,
                        ""TheDateTime"": ""2017-08-22T15:32:10.7023008-04:00""
                    }";
                    break;

            }

            /* START THE MEAT OF THIS PROCEDURE */

            Newtonsoft.Json.Linq.JObject jobj = Newtonsoft.Json.Linq.JObject.Parse(jsonContent);

            IList<string> messages;
            bool valid = jobj.IsValid(jschem, out messages);

            /* ENDTHE MEAT OF THIS PROCEDURE */


            if (!valid)
            {
                string errorMsg = "i=" + i.ToString() + ":" + string.Join(",", messages);
                Console.WriteLine(string.Empty);
                Console.WriteLine(string.Empty);
                Console.WriteLine(errorMsg);
            }
            else
            {
                Console.WriteLine(string.Empty);
                Console.WriteLine(string.Empty);
                Console.WriteLine("i=" + i.ToString() + ":" + "Good json Yes");

                MyCoolObject thisShouldWorkWhenValidationPasses = Newtonsoft.Json.JsonConvert.DeserializeObject<MyCoolObject>(jsonContent);

            }

            Console.WriteLine(string.Empty);
            Console.WriteLine("--------------------------------------------------");
            Console.WriteLine(string.Empty);


        }

和包

<?xml version="1.0" encoding="utf-8"?>
<packages>

  <package id="Newtonsoft.Json" version="10.0.2" targetFramework="net45" />
  <package id="Newtonsoft.Json.Schema" version="3.0.3" targetFramework="net45" />

</packages>

所以发生的事情是,当i = 2时,json-schema会通过,但是MyCoolObject thisShouldWorkWhenValidationPasses会抛出异常....

  

i = 2:好json是

     

未处理的异常:Newtonsoft.Json.JsonSerializationException:错误   转换价值&#34; NOTAGUID-3333-3333-3333-333333333333&#34;输入   &#39;的System.Guid&#39 ;. Path&#39; TheUuid&#39;,第2行,第77位.---&gt;   System.ArgumentException:无法从System.String转换或转换   到System.Guid。

:(

我试图让json-schema更早失败。

最终游戏是执行json-schema-validation而不会抛出异常。然后&#34;一切都很清楚&#34;尝试加载对象。我的真实内容更复杂,但这个小型演示显示了问题。

我还 替换了 这个程序的主要内容&#34;使用以下代码

            /* START THE MEAT OF THIS PROCEDURE */

            Newtonsoft.Json.JsonTextReader reader = new Newtonsoft.Json.JsonTextReader(new System.IO.StringReader(jsonContent));

            Newtonsoft.Json.Schema.JSchemaValidatingReader validatingReader = new Newtonsoft.Json.Schema.JSchemaValidatingReader(reader);
            validatingReader.Schema = JSchema.Parse(schemaJson);

            IList<string> messages = new List<string>();
            validatingReader.ValidationEventHandler += (o, a) => messages.Add(a.Message);

            Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer();
            /* below is the issue with this code..you still try to serialize the object...and that can throw an exception */
            MyCoolObject p = serializer.Deserialize<MyCoolObject>(validatingReader);
            bool valid = !messages.Any();

            /* END THE MEAT OF THIS PROCEDURE */

但同样,这可能会被抛出异常......试图验证。

1 个答案:

答案 0 :(得分:1)

感谢Jeroen Mostert的提示,这使我得到了这个解决方案:

            /* START THE MEAT OF THIS PROCEDURE */

            IList<string> deserializeMessages = new List<string>();

            /* first get any serialization issues */
            MyCoolObject p = JsonConvert.DeserializeObject<MyCoolObject>(jsonContent,
                new JsonSerializerSettings
                {
                    Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args)
                    {
                        deserializeMessages.Add(args.ErrorContext.Error.Message);
                        args.ErrorContext.Handled = true;
                    }
                });

            IList<string> jsonSchemaMessages = new List<string>();
            bool jsonSchemaIsValid = true;
            /* now, only if there were no serialization issues, look at the schema */
            if (!deserializeMessages.Any())
            {
                Newtonsoft.Json.Linq.JObject jobj = Newtonsoft.Json.Linq.JObject.Parse(jsonContent);
                jsonSchemaIsValid = jobj.IsValid(jschem, out jsonSchemaMessages);
            }

            IEnumerable<string> allMessages = deserializeMessages.Union(jsonSchemaMessages);

            bool overallValid = !allMessages.Any();

            /* END THE MEAT OF THIS PROCEDURE */

这为我提供了这种情况所需的输出:

  

i = 0:好json是

           

i = 1:属性&#39; TheUuidXXX&#39;尚未定义,架构没有   允许其他属性。 Path&#39; TheUuidXXX&#39;,第2行,位置   41.,对象缺少必需的属性:TheUuid。路径&#39;&#39;,第1行,第1位。

           

i = 2:转换值时出错&#34; NOTAGUID-3333-3333-3333-333333333333&#34;至   输入&#39; System.Guid&#39;。 Path&#39; TheUuid&#39;,第2行,第77位。

           

i = 3:解析值时遇到意外的字符:o。路径   &#39; TheInteger&#39;,第3行,第41位,错误解析布尔值。路径   &#39; TheInteger&#39;,第3行,第42位。

           

i = 4:无法将字符串转换为DateTime:NOTADATE。路径   &#39; TheDateTime&#39;,第4行,第50位。

           

按ENTER键退出

我仍然把头环绕着它。但是在我的特定情况下(我想立即回复http请求有一个json问题),它可以工作。

我没有将此标记为&#34;答案&#34;如果有人想出更好的东西。

注意,我将我的i for循环改为&lt; 5

for (int i = 0; i < 5; i++)