Search code examples
asp.net-coredefault-value

Asp.Net Core 5 [FromQuery] default value in model bindings


Summary

Is there a way to set default values if they are omitted in the request?

Details

I'm have a model for query parameters which define default values. However, the default values are not set when the query parameter is omitted in the request.

The request is defined like this

[HttpGet("list")]
public async Task<IList<Entry>> GetJsonAsync([FromQuery] Query query)
            => await _store.QueryAsync(query);

And the query like this

public class Query
{
    public DateTime? After { get; set; } = DateTime.MinValue;
    public TimeSpan? Duration { get; set; } = TimeSpan.MaxValue;
}

The requests looks like this

http://localhost/api/list?after=2021-10-08T08:35Z&duration=10d
http://localhost/api/list

If I call it without the query parameters After and Duration will be null.

If I make them non-nullable, I get validation errors.

public class Query
{
    public DateTime After { get; set; } = DateTime.MinValue;
    public TimeSpan Duration { get; set; } = TimeSpan.MaxValue;
}

Results in this

"errors": {
    "After": [
        "The field must be set"
    ],
    "Duration": [
        "The field must be set"
    ]
}

Is there an easy way to set After and Duration default values if they are omitted in the request?


Solution

  • I managed to solve it with an IActionFilter, thanks to How to automatically set default value of API model's property with value from appSettings.json?.

    If there is a better solution, please let me know if there is a better way.

    public class InitPassengerCountingQueryFilter : IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext context)
        {
    
        }
    
        public void OnActionExecuting(ActionExecutingContext context)
        {
            var q = context.ActionArguments.Values.OfType<Query>().FirstOrDefault();
    
            if (q != null)
            {
                q.After = q.After ?? DateTime.MinValue;
                q.Duration = q.Duration ?? TimeSpan.MaxValue;
            }
        }
    }
    

    And

    services.AddControllers(options =>
    {
        options.Filters.Add<InitPassengerCountingQueryFilter>();
    });