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

.NET 8 Minimal API中AsParameters无法加载查询字符串嵌套对象

问题:Minimal API结合MediatR时嵌套属性无法通过查询字符串绑定

问题场景

使用的查询字符串:

/api/Relogio?Name=&ProductRef.Code=asdsadsadsadsadasdsasadsa&ProductRef.Year=12&CurrentPage=1&PageSize=15

简单属性(如Name、CurrentPage)能正常赋值,但嵌套的ProductRef.Code、ProductRef.Year无法填充到请求对象的ProductRef属性中。

相关代码

请求类定义:

public class GetAllProductsRequest : IRequest<PaginatedList<GetProductResponse>>
{
    public string? Name { get; set; }
    public ProductRef? ProductRef { get; set; } // 该对象无法被赋值
    public int CurrentPage { get; set; } = 1;
    public int PageSize { get; set; } = 15;
}

ProductRef类定义:

public class ProductRef
{
    public string Code { get; set; } = string.Empty;
    public int? Year { get; set; }
}

Minimal API Action:

group.MapGet("/", async (IMediator mediator, [AsParameters] GetAllProductsRequest request) =>
{
    var result = await mediator.Send(request);
    return result;
});

使用环境:.NET 8.0.2 x64

原因

.NET Minimal API的[AsParameters]特性绑定逻辑仅支持扁平化的顶级属性映射,不会自动处理嵌套引用类型的实例化与属性填充。它的设计目标是将多个独立参数合并到一个对象中,而非处理复杂的嵌套模型绑定场景,因此无法识别ProductRef.Code这类点符号的嵌套参数结构。

解决方案

方案1:手动提取并赋值嵌套属性

直接从HttpRequest中获取查询参数,手动实例化ProductRef并赋值:

group.MapGet("/", async (IMediator mediator, [AsParameters] GetAllProductsRequest request, HttpRequest httpRequest) =>
{
    request.ProductRef = new ProductRef
    {
        Code = httpRequest.Query["ProductRef.Code"].ToString(),
        Year = int.TryParse(httpRequest.Query["ProductRef.Year"], out var year) ? year : null
    };
    var result = await mediator.Send(request);
    return result;
});

方案2:移除[AsParameters],使用默认模型绑定

去掉[AsParameters]特性,让Minimal API使用默认的模型绑定机制,该机制支持点符号的嵌套属性绑定:

group.MapGet("/", async (IMediator mediator, GetAllProductsRequest request) =>
{
    var result = await mediator.Send(request);
    return result;
});

注:此方式要求嵌套类(ProductRef)存在无参构造函数(你的代码已满足,因为属性有默认值初始化),模型绑定会自动实例化嵌套对象并填充属性。

方案3:自定义绑定器

实现IBinder接口,为GetAllProductsRequest编写自定义绑定逻辑,处理嵌套属性的解析:

public class GetAllProductsRequestBinder : IBinder
{
    public async ValueTask BindAsync(BinderContext context)
    {
        var query = context.HttpContext.Request.Query;
        var request = new GetAllProductsRequest
        {
            Name = query["Name"],
            CurrentPage = int.TryParse(query["CurrentPage"], out var page) ? page : 1,
            PageSize = int.TryParse(query["PageSize"], out var size) ? size : 15,
            ProductRef = new ProductRef
            {
                Code = query["ProductRef.Code"],
                Year = int.TryParse(query["ProductRef.Year"], out var year) ? year : null
            }
        };
        context.Result = ModelBindingResult.Success(request);
    }
}

然后在Action中使用自定义绑定器:

group.MapGet("/", async (IMediator mediator, [BinderType(typeof(GetAllProductsRequestBinder))] GetAllProductsRequest request) =>
{
    var result = await mediator.Send(request);
    return result;
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 02:15:15