.NET Core Web API 可选查询参数仍然不为空

问题描述 投票:0回答:2

StackOverflow 上有很多类似的问题,但没有人谈论我的问题。

我有 REST API 控制器,方法如下:

    [HttpGet("Lists")]
    public Codebook GetFilterLists([FromQuery] FilterQuery? filterQuery = null)
    {
        // some select and return code
    }

FilterQuery
类的所有属性在 Swagger UI 上显示为可选。 当我将它们全部留空并单击“执行”按钮时,Swagger UI 会进行以下 GET 查询:
https://localhost:7137/api/PublicWeb/Lists

即便如此,

filterQuery
参数也具有值 - 具有默认值的
filterQuery
实例。 enter image description here

我尝试更改 Program.cs 中的

JsonSerializerOptions.DefaultIgnoreCondition
设置,但对此没有效果。

你知道我做错了什么吗?

.net-core asp.net-core-webapi
2个回答
0
投票

好吧,一开始我想分享的是,你可能知道nullableOptional是完全不同的概念。如果您使用

int?
声明一个参数,将其标记为可为空,但它不是可选的:您必须传递非空整数值或 null。但是,添加
= null
是声明 可选参数 的默认值所需的语法。您可以在这里查看更多详细信息。

.NET Core Web API 可选查询参数仍然不为空。你知道我做错了什么吗?

您所得到的行为是预期的,因为如果属性是简单类型,则该属性被设置为 null 或默认值,但您的属性是复杂类型,因此,值设置不为 null。

除此之外,不可空值类型设置为

default(T)
。意味着它创建了一个实例,但你的实例可以为空,这违反了约定,因此它不会找到任何与其匹配的源属性,从而导致不为空。

注意:您可以在官方文档中找到更多详细信息

我尝试更改 JsonSerializerOptions.DefaultIgnoreCondition 设置 在 Program.cs 中,但对此没有任何影响。

不,JsonSerializerOptions 无法解决您的问题。您需要自定义模型绑定器来实现您所期望的。这里我给你提供了一个示例图,但是你必须根据你的要求来改进它。

定制模型活页夹:

public class NullEntityBinder : IModelBinder
    {
       
        public NullEntityBinder()
        {
         
        }

        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }

             var model = new FilterQuery();



            if (bindingContext.ValueProvider.GetValue("AreaOfAdjustmentId").FirstOrDefault() != null)
            {
                model.AreaOfAdjustmentId = Convert.ToUInt32(bindingContext.ValueProvider.GetValue("AreaOfAdjustmentId").FirstOrDefault());
            }

            if (bindingContext.ValueProvider.GetValue("DocumentName").FirstOrDefault() != null)
            {
                model.DocumentName = bindingContext.ValueProvider.GetValue("DocumentName").FirstOrDefault();
            }

            if (model.AreaOfAdjustmentId == null && model.DocumentName == null)
            {
                bindingContext.Result = ModelBindingResult.Success(null);
            }

            bindingContext.Result = ModelBindingResult.Success(model);
            return Task.CompletedTask;
        }
    }

用活页夹包裹你的模型:

[ModelBinder(BinderType = typeof(NullEntityBinder))]
public class FilterQuery
{
   
    public uint? AreaOfAdjustmentId { get; set; }
    public string? DocumentName { get; set; }
   
}

注意: 在我的测试中我使用了两个属性进行演示;您还需要根据您的其他属性实现逻辑。

输出:

enter image description here

注意:如果您想了解更多详细信息,您可以在此处查看我们的官方文档


0
投票

据我所知,模型绑定是如何工作的,现在这是不可能的;它总是尝试用默认值填充类。

我认为,从他们如何设置路由和绑定的角度来看,推荐的方法是使用两种不同的路由来处理两种情况:一种是如果您试图给它一个过滤器查询,另一种是如果您不这样做。或者只是检查 filterquery 对象内部的值,看看它是否有效或只是默认值。

© www.soinside.com 2019 - 2024. All rights reserved.