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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 19:05:07