Required query string parameter in ASP.NET Core

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 request parameters. That I would like to have one of these (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 ASP.NET to do this check even before calling my controller.

I would like to use Newtonsoft's RequiredAttribute to use the same attributes that I already use to validate required properties in the PUT / POST content, but since the URL is not a JSON string, it is not explicitly used.

Any suggestion for ASP.NET Core to automatically validate the required request parameters?

Note that I know I can code the validation myself using nullable query parameters, but this is better than letting ASP.NET do the validation before calling my controller, thereby keeping my controller clean.

+7


source to share


4 answers


You might consider using wireframe model binding

According to the documentation here: Customize the model binding behavior using 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 using [BindRequired]

or [BindNever]

attributes.

So I suggest you add 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 binding and update the state of the model so that you can check the state of the model in 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();
    }        
}

      

Another option is to create a custom model binder that will throw an error if the required query string is missing.

Reference: Custom Model Binding

+19


source


Let the framework work for you. Here's one solution as there seem to be multiple ways to do the same 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 received.



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() };
    }        
}

      

+2


source


Use attribute routing and specify each required parameter in the HttpGet attribute of the function.

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

      

This would require, for example, / 5, and allow / 5? B = 6 request request parameters.

+1


source


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

-3


source







All Articles