web-dev-qa-db-fra.com

Paramètre de chaîne de requête obligatoire dans ASP.NET Core

En utilisant ASP.NET Core 1.1 avec VS2015 (sdk 1.0.0-preview2-003131), j'ai le contrôleur suivant:

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

Comme vous pouvez le voir, j'ai deux paramètres de requête. Ce que j'aimerais, c'est que l'un d'eux (ex: A) soit requis. Autrement dit, je voudrais utiliser un attribut (si possible) pour dire que cet attribut est requis. Ensuite, j'aimerais qu'ASP.NET fasse cette validation avant même d'appeler mon contrôleur.

J'aurais aimé utiliser le Newtonsoft RequiredAttribute pour utiliser les mêmes attributs que j'utilise déjà pour valider les propriétés requises dans le contenu PUT/POST, mais comme l'url n'est pas une chaîne JSON, c'est évidemment non utilisé.

Une suggestion pour qu'ASP.NET Core vérifie automatiquement les paramètres de requête requis?

Notez que je sais que je peux coder la vérification moi-même en utilisant des paramètres de requête Nullable mais cela bat le but de laisser ASP.NET faire la validation avant d'appeler mon contrôleur, gardant ainsi mon contrôleur en ordre.

8
mabead

Vous pouvez envisager d'utiliser la fonction de liaison de modèle du cadre

Selon la documentation ici: Personnaliser le comportement de liaison du modèle avec des attributs

MVC contient plusieurs attributs que vous pouvez utiliser pour diriger son comportement de liaison de modèle par défaut vers une autre source. Par exemple, vous pouvez spécifier si la liaison est requise pour une propriété ou si cela ne doit jamais se produire en utilisant le [BindRequired] ou [BindNever] les attributs.

Je vous suggère donc d'ajouter un BindRequiredAttribute à la propriété model.

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

À partir de là, le framework doit pouvoir gérer l'état du modèle de liaison et de mise à jour afin que vous puissiez vérifier l'état du modèle dans l'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();
    }        
}

L'autre option serait de créer un classeur de modèle personnalisé qui ferait défaut à l'action si la chaîne de requête requise n'est pas présente.

Référence: liaison de modèle personnalisé

19
Nkosi

Laissez le cadre faire le travail pour vous. Voici une solution, car il semble qu'il existe un certain nombre de façons d'accomplir la même chose dans ASP.NET Core. Mais c'est ce qui fonctionne pour moi et c'est assez simple. Cela semble être une combinaison de certaines des réponses déjà données.

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
Jeff Magill

Utilisez le routage d'attributs et répertoriez chaque paramètre requis dans l'attribut HttpGet de la fonction.

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

Cela nécessitera par exemple/5 et autorisera/5? B = 6 paramètres d'URL de requête.

1
Esa Komulainen