Search code examples
c#.netasp.net-core.net-8.0minimal-apis

AsParameters in Minimal Apis does not load nested objects from the querystring


I'm using Minimal Apis together with MediatR and I'm having a problem passing parameters via querystring, below the querystring:

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

The simple properties like Name are being filled, but the complex ProductRef.Code and ProductRef.Year are not being filled

Below the request class

public class GetAllProductsRequest : IRequest<PaginatedList<GetProductResponse>>
{
    public string? Name { get; set; }
    public ProductRef? ProductRef { get; set; } // This Object not loaded
    public int CurrentPage { get; set; } = 1;
    public int PageSize { get; set; } = 15;
}

The ProductRef class not being populated

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

"Action" from Minimal Api, uses the AsParameters attribute

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

Why are nested complex properties not being populated?

Version used: .NET 8.0.2 x64


Solution

  • From the docs:

    AsParametersAttribute enables simple parameter binding to types and not complex or recursive model binding.

    I assume this case falls under "complex" one.

    TBH for me it does not only "skips" filling the ProductRef but produces exception on app startup (since ProductRef is inferred as body parameter by default):

    InvalidOperationException: Body was inferred but the method does not allow inferred body parameters.

    The workaround would be custom binding with BindAsync. Something to get you started:

    public class ProductRef
    {
        // ...
    
        public static ValueTask<ProductRef> BindAsync(HttpContext context,
            ParameterInfo parameter)
        {
            var productRef = new ProductRef
            {
                Code = context.Request.Query[$"{parameter.Name}.Code"],
                // ....
            };
            return ValueTask.FromResult(productRef);
        }
    }