ASP.NET Core 7如何检测Http POST请求中的额外属性?
在ASP.NET Core 7中检测[FromBody]绑定的额外属性
默认情况下,ASP.NET Core使用的System.Text.Json序列化器会自动忽略请求体中目标类未定义的额外属性,不会触发任何错误。如果需要检测并拦截这类请求,可以通过以下几种方式实现:
方法一:修改JSON序列化配置,启用未知属性报错
直接配置全局Json选项,关闭"忽略未知属性"的开关,这样当请求体包含未定义属性时,反序列化会直接抛出异常,返回400 Bad Request。
在Program.cs中添加配置:
builder.Services.AddControllers() .AddJsonOptions(options => { // 关闭忽略未知属性,遇到未定义属性时抛出JsonException options.JsonSerializerOptions.IgnoreUnknownValues = false; });
这种方式实现简单,但错误信息比较笼统,无法明确指出具体是哪个属性未定义。
方法二:使用自定义资源过滤器检测未知属性
通过自定义过滤器,可以在模型绑定前读取请求体,解析JSON后对比目标类的属性,精准找出未定义的属性并返回自定义错误信息。
- 实现自定义资源过滤器:
public class DetectUnknownPropertiesFilter : IAsyncResourceFilter { public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { // 定位到目标参数类型(这里以SomeData为例) var targetParam = context.ActionDescriptor.Parameters .FirstOrDefault(p => p.ParameterType == typeof(SomeData)); if (targetParam == null) { await next(); return; } // 缓存请求体,避免后续绑定无法读取 var originalBody = context.HttpContext.Request.Body; try { using var memoryStream = new MemoryStream(); await originalBody.CopyToAsync(memoryStream); memoryStream.Position = 0; context.HttpContext.Request.Body = memoryStream; // 读取并解析JSON内容 var jsonContent = await new StreamReader(memoryStream).ReadToEndAsync(); memoryStream.Position = 0; // 重置流位置,供后续模型绑定使用 using var jsonDoc = JsonDocument.Parse(jsonContent); var rootElement = jsonDoc.RootElement; // 获取目标类的所有属性名(考虑JsonPropertyName特性和序列化命名策略) var knownProps = typeof(SomeData).GetProperties() .Select(prop => { var jsonAttr = prop.GetCustomAttribute<JsonPropertyNameAttribute>(); return jsonAttr?.Name ?? context.HttpContext.RequestServices .GetRequiredService<IOptions<JsonOptions>>() .Value.JsonSerializerOptions.PropertyNamingPolicy .ConvertName(prop.Name); }) .ToHashSet(StringComparer.OrdinalIgnoreCase); // 遍历JSON属性,检查是否存在未定义项 foreach (var jsonProp in rootElement.EnumerateObject()) { if (!knownProps.Contains(jsonProp.Name)) { context.ModelState.AddModelError("", $"请求包含未定义的属性:{jsonProp.Name}"); context.Result = new BadRequestObjectResult(context.ModelState); return; } } await next(); } finally { context.HttpContext.Request.Body = originalBody; } } }
- 注册过滤器(全局或控制器级):
全局注册在Program.cs:
builder.Services.AddControllers(options => { options.Filters.Add<DetectUnknownPropertiesFilter>(); }) .AddJsonOptions(options => { // 保持默认忽略未知属性,避免提前抛出异常 options.JsonSerializerOptions.IgnoreUnknownValues = true; });
如果只需要针对特定控制器生效,可在控制器上添加[ServiceFilter(typeof(DetectUnknownPropertiesFilter))]特性。
这种方式可以精准控制检测逻辑,返回友好的错误信息,灵活性高。
方法三:使用自定义JsonConverter实现严格反序列化
通过自定义Json转换器,在反序列化过程中直接检测未知属性,抛出明确的错误。
- 实现自定义转换器:
public class StrictJsonConverter<T> : JsonConverter<T> where T : class, new() { public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 解析JSON文档 using var jsonDoc = JsonDocument.ParseValue(ref reader); var rootElement = jsonDoc.RootElement; // 获取目标类的已知属性名 var knownProps = typeToConvert.GetProperties() .Select(prop => { var jsonAttr = prop.GetCustomAttribute<JsonPropertyNameAttribute>(); return jsonAttr?.Name ?? options.PropertyNamingPolicy.ConvertName(prop.Name); }) .ToHashSet(StringComparer.OrdinalIgnoreCase); // 检查未知属性 foreach (var jsonProp in rootElement.EnumerateObject()) { if (!knownProps.Contains(jsonProp.Name)) { throw new JsonException($"请求中存在未定义的属性:{jsonProp.Name}"); } } // 执行正常反序列化 return jsonDoc.Deserialize<T>(options); } public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { JsonSerializer.Serialize(writer, value, options); } }
- 注册转换器:
在Program.cs中配置,可针对全局或特定类型:
builder.Services.AddControllers() .AddJsonOptions(options => { // 为SomeData类型添加严格转换器 options.JsonSerializerOptions.Converters.Add(new StrictJsonConverter<SomeData>()); });
这种方式适合需要对特定类型进行严格校验的场景,错误信息明确,但需要为每个目标类型单独注册转换器(或通过泛型批量处理)。
内容的提问来源于stack exchange,提问作者Grant Nilsson
相关产品推荐
相关产品推荐

