ASP.NET Core MVC:默认模型绑定外收集POST原始键值对
ASP.NET Core MVC中获取POST提交的原始键值对
我需要在ASP.NET Core MVC的Action中获取POST提交的原始键值对用于后续处理,为此定义了以下泛型类:
public class ValidationRequest<T> where T : class { public string Form { get; set; } = string.Empty; public required T Fields { get; set; } public Dictionary<string, string> RawPostedKeyValues { get; set; } = []; }
对应的Action方法如下:
[HttpPost] public async Task<JsonResult> ValidateTestFormAsync([FromBody] ValidationRequest<PersonModel> personValidationRequest) { //业务逻辑 }
其中PersonModel是常规的POST模型。我的核心需求是:在默认模型绑定和验证之外,让RawPostedKeyValues属性包含所有与Fields类型属性名匹配的POST原始键值对(防止过度提交),且键名要遵循ModelState验证错误的默认命名规则(即Fields.属性名格式)。
之前尝试过在属性级添加自定义逻辑,但由于POST数据中没有对应RawPostedKeyValues的键,逻辑并未触发。也曾考虑为ValidationRequest类使用自定义模型绑定器,但不知道如何在保留默认绑定的同时读取请求体来填充该属性。
解决方案:自定义JSON转换器(工厂模式实现)
通过工厂模式结合自定义JSON转换器,我实现了需求,完整代码如下:
转换器工厂类
public class ValidationRequestJsonConverter : JsonConverterFactory { public override bool CanConvert(Type typeToConvert) { if (!typeToConvert.IsGenericType) return false; Type generic = typeToConvert.GetGenericTypeDefinition(); return (generic == typeof(ValidationRequest<>)); } public override JsonConverter CreateConverter(Type type, JsonSerializerOptions options) { Type argumentType = type.GetGenericArguments()[0]; JsonConverter converter = (JsonConverter)Activator.CreateInstance( typeof(ValidationRequestInnerJsonConverter<>).MakeGenericType(new Type[] { argumentType }), BindingFlags.Instance | BindingFlags.Public, binder: null, args: [options], culture: null)!; return converter; } }
泛型转换器实现类
internal class ValidationRequestInnerJsonConverter<T> : JsonConverter<ValidationRequest<T>> where T : class { // 必须添加此构造函数,否则运行时会报错 public ValidationRequestInnerJsonConverter(JsonSerializerOptions options) { } public override ValidationRequest<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var jsonDocument = JsonDocument.ParseValue(ref reader); var root = jsonDocument.RootElement; var form = root.GetProperty("form").GetString(); var fieldsJson = root.GetProperty("fields").GetRawText(); var fieldObject = JsonSerializer.Deserialize<T>(fieldsJson, options) ?? Activator.CreateInstance<T>(); var rawPostedKeyValues = new Dictionary<string, string?>(); foreach (var property in root.GetProperty("fields").EnumerateObject()) { rawPostedKeyValues[$"Fields.{property.Name}"] = property.Value.ToString(); } return new ValidationRequest<T> { Form = form, Fields = fieldObject, RawPostedKeyValues = rawPostedKeyValues }; } public override void Write(Utf8JsonWriter writer, ValidationRequest<T> value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WriteString("form", value.Form); writer.WritePropertyName("fields"); JsonSerializer.Serialize(writer, value.Fields, options); writer.WritePropertyName("rawPostedKeyValues"); JsonSerializer.Serialize(writer, value.RawPostedKeyValues, options); writer.WriteEndObject(); } }
内容的提问来源于stack exchange,提问作者SventoryMang
相关产品推荐
相关产品推荐

