32

Using ASP.NET Core 1.1 with VS2015 (sdk 1.0.0-preview2-003131), I have the following controller:

public class QueryParameters
{
    public int A { get; set; }
    public int B { get; set; }
}

[Route("api/[controller]")]
public class ValuesController : Controller
{
    // GET api/values
    [HttpGet]
    public IEnumerable<string> Get([FromQuery]QueryParameters parameters)
    {
        return new [] { parameters.A.ToString(), parameters.B.ToString() };
    }        
}

As you can see, I have two query parameters. What I would like is to have one of them (ex: A) to be required. That is, I would like to use an attribute (if possible) to say that this attribute is required. Then, I would like like ASP.NET to do this validation before even calling my controller.

I would have liked to use the Newtonsoft RequiredAttribute to use the same attributes as I already use to validate the required properties in the PUT/POST content, but since the url is not a JSON string, it is obviously not used.

Any suggestion to have ASP.NET Core automatically check for required query parameters?

Note that I know that I can code the check myself using nullable query parameters but that beats the purpose of letting ASP.NET do the validation before calling my controller, thus keeping my controller tidy.

5 Answers 5

58

In ASP.NET Core 2.1 and above you can use top level parameters validation. You can put attributes on parameters

    [HttpGet]
    public IActionResult GetDices([BindRequired, Range(1, 6)]int number)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest("Invalid number");
        }

            return Ok(_diceRepo.GetDices(number));
    }

More about this https://programmingcsharp.com/asp-net-parameter-validation/#Top-level_node_validation

Sign up to request clarification or add additional context in comments.

2 Comments

using Microsoft.AspNetCore.Mvc.ModelBinding; is what I used to reference the attribute, BindRequired
Why do we need BindRequired? I didn't see any difference in .NET 6
37

You can consider using the model binding feature of the framework

According to documentation here: Customize model binding behavior with attributes

MVC contains several attributes that you can use to direct its default model binding behavior to a different source. For example, you can specify whether binding is required for a property, or if it should never happen at all by using the [BindRequired] or [BindNever] attributes.

So I suggest you add a BindRequiredAttribute to the model property.

public class QueryParameters
{
    [BindRequired]
    public int A { get; set; }
    public int B { get; set; }
}

From there the framework should be able to handle the binding and updating model state so that you can check the state of the model in the action

[Route("api/[controller]")]
public class ValuesController : Controller
{
    // GET api/values
    [HttpGet]
    public IActionResult Get([FromQuery]QueryParameters parameters)
    {    
        if (ModelState.IsValid)
        {
            return Ok(new [] { parameters.A.ToString(), parameters.B.ToString() });
        }
        return BadRequest();
    }        
}

The other option would be to create a custom model binder that would fault the action if the required query string is not present.

Reference: Custom Model Binding

1 Comment

What if you want the property to have a different name. Before you could've have [FromQuery(Name = "$A")]
6

Let the framework do the work for you. Here is one solution, as it appears there are a number of ways to accomplish the same thing in ASP.NET Core. But this is what works for me and is quite simple. It seems to be a combination of some of the answers already given.

public class QueryParameters
{
    [Required]
    public int A { get; set; }

    public int B { get; set; }
}

[Route("api/[controller]")]
public class ValuesController : Controller
{
    // GET api/values
    // [HttpGet] isn't needed as it is the default method, but ok to leave in
    // QueryParameters is injected here, the framework takes what is in your query string and does its best to match any parameters the action is looking for. In the case of QueryParameters, you have A and B properties, so those get matched up with the a and b query string parameters
    public IEnumerable<string> Get(QueryParameters parameters)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(); // or whatever you want to do
        }

        return new [] { parameters.a.ToString(), parameters.b.ToString() };
    }        
}

Comments

-1

Use model validation. You can define a ViewModel and use DataAnnotations to mark property A as [Required]. Then in your action just check if ModelState.IsValid. You can also easily do this using an action filter as shown in this article: https://msdn.microsoft.com/en-us/magazine/mt767699.aspx

Comments

-2

Use attribute routing and list each required parameter in the function's HttpGet attribute.

[Route("api/[controller]")]
public class ValuesController : Controller
{
    [HttpGet("{A}")]
    public IEnumerable<string> Get(int A, int B)
    {
       return new [] { A.ToString(), B.ToString() };
    }
}

This will require e.g /5 and allow /5?B=6 query url parameters.

1 Comment

The OP is asking how to require query parameters, not URL parameters.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.