You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core WEB API Modelbinding:如何使用JSON Schema实现验证

实现方案总览

ASP.NET Core没有内置JSON Schema校验的原生中间件,你可以通过两种路径实现需求:

  • 全局中间件:对所有PUT/POST/PATCH请求统一校验,适合校验规则完全统一的场景
  • 动作过滤器/端点过滤器:可以按接口指定不同的JSON Schema,灵活度更高,是大部分场景的首选方案
前置准备

先根据你项目使用的序列化器安装对应校验库:

  • 若使用System.Text.Json作为默认序列化器:安装JsonSchema.Net NuGet包
  • 若使用Newtonsoft.Json作为默认序列化器:安装Newtonsoft.Json.Schema NuGet包

你可以将JSON Schema文件的属性设置为嵌入式资源,或者放到配置目录下,通过配置项读取路径,符合你希望在Startup中通过配置选项注册的需求:

  1. 在appsettings.json中添加Schema路径配置:
"JsonSchemaSettings": {
  "CreateUserSchema": "YourProjectName.Schemas.CreateUserSchema.json",
  "UpdateOrderSchema": "YourProjectName.Schemas.UpdateOrderSchema.json"
}
  1. 定义配置类并在Startup中注册:
// 配置类
public class JsonSchemaSettings
{
    public string CreateUserSchema { get; set; }
    public string UpdateOrderSchema { get; set; }
}

// Startup.cs ConfigureServices方法中注册
services.Configure<JsonSchemaSettings>(Configuration.GetSection("JsonSchemaSettings"));
推荐实现:动作过滤器(全版本.NET Core适用)

该方案支持按接口单独指定Schema,不需要全局生效时不用注册全局过滤器,仅在需要校验的接口上加Attribute即可:

public class JsonSchemaValidationAttribute : ActionFilterAttribute
{
    private readonly JsonSchema _schema;
    // 传入对应配置项的Key即可加载对应Schema
    public JsonSchemaValidationAttribute(string schemaConfigKey)
    {
        // 读取配置
        var config = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")
            .Build();
        var schemaPath = config.GetValue<string>($"JsonSchemaSettings:{schemaConfigKey}");
        
        // 读取嵌入式Schema文件,以下为Newtonsoft.Json.Schema示例,System.Text.Json逻辑类似
        using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(schemaPath);
        using var reader = new StreamReader(stream);
        _schema = JsonSchema.Parse(reader.ReadToEnd());
    }

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        // 仅校验PUT/POST/PATCH请求
        var method = context.HttpContext.Request.Method;
        if (method is not HttpMethods.Post and not HttpMethods.Put and not HttpMethods.Patch)
        {
            base.OnActionExecuting(context);
            return;
        }

        // 开启请求体缓冲,避免读完之后后续中间件/控制器读不到请求体
        context.HttpContext.Request.EnableBuffering();
        using var reader = new StreamReader(context.HttpContext.Request.Body, leaveOpen: true);
        var requestBody = reader.ReadToEndAsync().Result;
        context.HttpContext.Request.Body.Position = 0;

        // 执行Schema校验
        var jObject = JObject.Parse(requestBody);
        IList<ValidationError> errors = new List<ValidationError>();
        if (!jObject.IsValid(_schema, out errors))
        {
            // 校验失败直接返回400
            context.Result = new BadRequestObjectResult(new
            {
                Message = "请求JSON格式不符合要求",
                Errors = errors.Select(e => e.Message)
            });
            return;
        }

        base.OnActionExecuting(context);
    }
}

使用方式:直接在需要校验的接口上贴Attribute即可

[HttpPost]
[JsonSchemaValidation(nameof(JsonSchemaSettings.CreateUserSchema))]
public IActionResult CreateUser([FromBody] CreateUserDto dto)
{
    // 业务逻辑
}

如果需要全局生效所有接口,在Startup的ConfigureServices中注册全局过滤器即可:

services.AddControllers(options =>
{
    options.Filters.Add<JsonSchemaValidationAttribute>();
});
中间件实现方案(全局统一校验)

如果你需要全局所有PUT/POST/PATCH请求都走同一套Schema校验,可以用中间件实现:

public class JsonSchemaValidationMiddleware
{
    private readonly RequestDelegate _next;
    private readonly JsonSchema _globalSchema;

    // 注入配置读取全局Schema
    public JsonSchemaValidationMiddleware(RequestDelegate next, IOptions<JsonSchemaSettings> schemaSettings)
    {
        _next = next;
        using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(schemaSettings.Value.GlobalSchema);
        using var reader = new StreamReader(stream);
        _globalSchema = JsonSchema.Parse(reader.ReadToEnd());
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // 仅校验JSON类型的PUT/POST/PATCH请求
        var method = context.Request.Method;
        if (method is HttpMethods.Post or HttpMethods.Put or HttpMethods.Patch 
            && context.Request.ContentType?.Contains("application/json") == true)
        {
            context.Request.EnableBuffering();
            using var reader = new StreamReader(context.Request.Body, leaveOpen: true);
            var requestBody = await reader.ReadToEndAsync();
            context.Request.Body.Position = 0;

            var jObject = JObject.Parse(requestBody);
            IList<ValidationError> errors = new List<ValidationError>();
            if (!jObject.IsValid(_globalSchema, out errors))
            {
                context.Response.StatusCode = StatusCodes.Status400BadRequest;
                context.Response.ContentType = "application/json";
                await context.Response.WriteAsJsonAsync(new
                {
                    Message = "请求JSON不符合Schema要求",
                    Errors = errors.Select(e => e.Message)
                });
                return;
            }
        }
        await _next(context);
    }
}

在Startup的Configure方法中注册中间件,位置放在路由中间件之后、控制器中间件之前即可:

app.UseRouting();
app.UseMiddleware<JsonSchemaValidationMiddleware>();
app.UseAuthorization();
app.MapControllers();
注意事项
  • 大文件上传接口不适用该方案,会将完整请求体读入内存,影响性能
  • 多Schema场景优先用过滤器方案,可灵活适配不同接口的校验规则

内容的提问来源于stack exchange,提问作者yBother

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 19:27:07