1

I have a GET endpoint in Asp.Net Core 2.2 where I want to return all records by default and if any query provided then I am returning a search query response. Here my query Dto never comes null even no query param provided. I want to keep Dto null when no query parameter provided.

My request Dto-

public sealed class SearchQueryDto
{
    public SearchQueryDto()
    {
        Limit = 10;
        Offset = 0;
    }

    public string Query { get; set; }
    public string PhoneNumber { get; set; }
    public string ClassificationId { get; set; }
    public int Offset { get; set; }
    public int Limit { get; set; }
}

My Endpoint-

[HttpGet]
public async Task<IActionResult> GetAllRecords([FromQuery] [CanBeNull] SearchQueryDto request)
{
    if (request != null) // always not null
    {
        return Ok(await _service.Search(request));
    }
    return Ok(await _service.GetAll());
}

Here I am expecting request to null when no query parameter provided but it always appears initialized.

SarangK
  • 559
  • 9
  • 24

3 Answers3

2

The docs lie:

Route data and query string values are used only for simple types.

This is simply not true. See also Bind query parameters to a model in ASP.NET Core, it just works.

This part of the docs is true:

When model binding occurs, the class is instantiated using the public default constructor.

So, the model class will always be instantiated. Unless it's bound from the body and the body is empty, corrupt or of the wrong content-type, but that's another story.

In your case, simply check whether the model doesn't have any properties set:

public sealed class SearchQueryDto
{
    private const int DefaultLimit = 10;
    private const int DefaultOffset = 0;

    public string Query { get; set; }
    public string PhoneNumber { get; set; }
    public string ClassificationId { get; set; }
    public int Offset { get; set; } = DefaultOffset;
    public int Limit { get; set; } = DefaultLimit;

    public bool IsDefault
    {
        get
        {
            return string.IsNullOrEmpty(Query)
                && string.IsNullOrEmpty(PhoneNumber)
                && string.IsNullOrEmpty(ClassificationId)
                && Offset == DefaultOffset
                && Limit == DefaultLimit;
        }
    }   
}

And then in your controller:

if (!request.IsDefault)
{
    // ...
}
CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • Well explained! Solves my problem in a cleaner way. Now the IsDefault parameter appears in swagger which I don't want it's to be there. – SarangK Nov 20 '19 at 07:04
  • 1
    You can use JsonIgnore to prevent it from being serialized and documented. Or make the property `internal` instead of `public`. – CodeCaster Nov 20 '19 at 08:04
0

you can set default null

[HttpGet] public async Task<IActionResult> GetAllRecords([FromQuery] SearchQueryDto request = null)

Ivan Martinyuk
  • 1,230
  • 1
  • 9
  • 13
0

Although you do not pass query string,the model would bind the default value,so you could not get null value.

In such case,you could fix it like below:

[HttpGet]
public async Task<IActionResult> GetAllRecords([FromQuery]SearchQueryDto request)
{
    var query = Request.QueryString.HasValue;
    if (query)
    {
        return Ok(await _service.Search(request));
    }
    return Ok(await _service.GetAll());
}
Rena
  • 30,832
  • 6
  • 37
  • 72