简体   繁体   中英

Using Json Schema Validator sample code from NewtonSoft and getting a 400 Bad Request

So I'm trying to wrap my head around writing an API for work and one portion of it is validating incoming JSON against a schema. I have created a simple schema as POC in order to get this API up and running. I am using NewtonSoft.Json.Schema as this seems to be the best way to achieve what I'm after, and I can't stress this enough, there is free sample code!

This is my sample schema, with sample json, showing that it validates.

https://www.jsonschemavalidator.net/s/jldyV4ng

In the sample code, a class ValidRequest is used and this contains the text of the schema and json, so I've attempted to leverage that code as-is.

Invoke-RestMethod -Method Post -Uri https://localhost:44392/api/jsonschema/validate -Body ('{"Schema":"https://gist.githubusercontent.com/jeffpatton1971/c2d3ee98a37766a2784ccd626b9b8ca2/raw/edee46a24c1439e09490e415fa27943a08b353dd/schema.json","Json":"{}"}') -ContentType application/json

valid errors
----- ------
False {@{message=Required properties are missing from object: checked, dimensions, id, name, price, tags.; lineNumber=1; linePosition=1; path=; value=System.Object[]; schema=; schemaId=http://example.com/root.json; schemaBaseUri=; er...

This appears to work as advertised, the validator is telling me that my empty json string is missing stuff. What I'm struggling with is when I attempt to pass in the correct json that works on the link above.

Invoke-RestMethod -Method Post -Uri https://localhost:44392/api/jsonschema/validate -Body ('{"Schema":"https://gist.githubusercontent.com/jeffpatton1971/c2d3ee98a37766a2784ccd626b9b8ca2/raw/edee46a24c1439e09490e415fa27943a08b353dd/schema.json","Json":{"checked":true,"dimensions":{"width":7,"height":8},"id":1,"name":"thing","price":1,"tags":[]}}') -ContentType application/json
Invoke-RestMethod : The remote server returned an error: (400) Bad Request.
At line:1 char:1
+ Invoke-RestMethod -Method Post -Uri https://localhost:44392/api/jsons ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

I feel that perhaps I've got the json string wrong in some fashion but I'm not clear. Below is the code from my POC. In my example I use the request.schema as a url and then I grab it from the URL passed in via WebClient. It parses the schema as you would expect, and for the null json string, it parsed that json as you would expect. When I pass in an actual json payload I get the error above. I have placed a breakpoint at the top of the ValidateResponse code, but I never get that far, so that error is thrown before I get to any code that I can trace.

Any help would be appreciated, I feel I'm doing something silly, the project is the asp.net core web api project, and I've followed the defaults and added an read/write api controller named JsonSchemaController. My startup.cs is below the JsonSchemaController.cs.

JsonSchemaController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Schema;
using System.Net;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace SchemaValidator.Properties
{
    [Route("api/[controller]")]
    [ApiController]
    public class JsonSchemaController : ControllerBase
    {
        public class ValidateRequest
        {
            public string Json { get; set; }
            public string Schema { get; set; }
        }

        public class ValidateResponse
        {
            public bool Valid { get; set; }
            public IList<ValidationError> Errors { get; set; }
        }

        // GET: api/<JsonSchemaController>
        [HttpGet]
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/<JsonSchemaController>/5
        [HttpGet("{id}")]
        public string Get(int id)
        {
            return "value";
        }

        [HttpPost]
        [Route("validate")]
        public ValidateResponse Valiate(ValidateRequest request)
        {
            WebClient wget = new System.Net.WebClient();
            var jsonSchema = wget.DownloadString(request.Schema);

            // load schema
            JSchema schema = JSchema.Parse(jsonSchema);
            JToken json = JToken.Parse(request.Json);

            // validate json
            IList<ValidationError> errors;
            bool valid = json.IsValid(schema, out errors);

            // return error messages and line info to the browser
            return new ValidateResponse
            {
                Valid = valid,
                Errors = errors
            };
        }

    }
}

Startup.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace SchemaValidator
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
                endpoints.MapControllerRoute(
                    "default", "{controller=Home}/{action=Index}/{id?}"
                    );
            });
        }
    }
}

Package Manager Output

PM> Install-Package newtonsoft.json
Restoring packages for C:\Users\JeffreyPatton\source\repos\SchemaValidator\SchemaValidator\SchemaValidator.csproj...
Installing NuGet package newtonsoft.json 13.0.1.
Committing restore...
Writing assets file to disk. Path: C:\Users\JeffreyPatton\source\repos\SchemaValidator\SchemaValidator\obj\project.assets.json
Restored C:\Users\JeffreyPatton\source\repos\SchemaValidator\SchemaValidator\SchemaValidator.csproj (in 22 ms).
Successfully installed 'Newtonsoft.Json 13.0.1' to SchemaValidator
Executing nuget actions took 1.1 sec
Time Elapsed: 00:00:01.6936888
PM> Install-Package newtonsoft.json.schema
Restoring packages for C:\Users\JeffreyPatton\source\repos\SchemaValidator\SchemaValidator\SchemaValidator.csproj...
Installing NuGet package newtonsoft.json.schema 3.0.14.
Committing restore...
Writing assets file to disk. Path: C:\Users\JeffreyPatton\source\repos\SchemaValidator\SchemaValidator\obj\project.assets.json
Restored C:\Users\JeffreyPatton\source\repos\SchemaValidator\SchemaValidator\SchemaValidator.csproj (in 9 ms).
Successfully installed 'Newtonsoft.Json.Schema 3.0.14' to SchemaValidator
Executing nuget actions took 1.01 sec
Time Elapsed: 00:00:01.4802313

The problem I'm seeing has to do with how the JSON is being constructed outside of the API. @dbc's post above with fiddler put me on the right track. Then working with postman helped me out even more.

{
    "Schema":"https://gist.githubusercontent.com/jeffpatton1971/c2d3ee98a37766a2784ccd626b9b8ca2/raw/edee46a24c1439e09490e415fa27943a08b353dd/schema.json",
    "Json": "{\"checked\":true,\"dimensions\":{\"width\":7,\"height\":8},\"id\":1,\"name\":\"thing\",\"price\":1,\"tags\":[]}"
}

This escaped json works as expected, I appreciate all the feedback.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM