Fermer

novembre 27, 2020

Renvoyer le résultat JSON avec le code d'état personnalisé dans ASP.NET Core


Contrôlez le format des réponses ASP.NET Core et apprenez à renvoyer un résultat JSON avec un code d'état personnalisé à l'aide de formateurs ou directement à partir de l'action.

Lorsque vous créez des API HTTP, vous voulez avoir le contrôle sur la façon dont vous répondez aux demandes en termes de modification des codes d'état et du format du corps. Dans cet article de blog, nous verrons comment nous pouvons contrôler la réponse JSON en personnalisant le code d'état dans ASP.NET Core.

Comment ASP.NET Core décide du format de réponse

Voyons d'abord comment un résultat JSON est en fait produit par ASP.NET Core, ce qui nous aidera à comprendre le mécanisme derrière le formatage des réponses. Lorsque nous développons un projet ASP.NET Core avec la configuration de l'API Web avec la commande CLI dotnet ci-dessous:

 dotnet new webapi --no-https --auth  =  Aucun

Notre fichier startup.cs ressemblera à ceci:

 public   class   Startup 
 {
     public   Startup  ( IConfiguration configuration ) 
     {
        Configuration  =  configuration ; 
    } 

     public  IConfiguration Configuration  {  get ;  } 

    
     public   void   ConfigureServices  ( IServiceCollection services ) 
     {
        services .  AddControllers  () ; 
    } 

    
     public   void   Configure  ( IApplicationBuilder app  IWebHostEnvironment env ) 
     {
         if   ( env .  IsDevelopment  () ) 
         {
            app .  UseDeveloperExceptionPage  () ; 
        } 

        app .  UseRouting  () ; 

        app .  UseAuthorization  () ; 

        app .  UseEndpoints  ( endpoints  = > 
         {
            endpoints .  MapControllers  () ; 
        } ) ; 
    } 
} 

Nous avons également un exemple de fichier de contrôleur nommé WeatherForecastController.cs qui a la forme ci-dessous:

 [ ApiController ] 
 [ Route  ] ( "[controller]" ) ] 
 public   class   WeatherForecastController  :  ControllerBase
 {
     private   static   readonly   string  []  Summaries  =   new  [] [19659014] {
         "Freezing"   "Bracing"   "Chilly"   "Cool"   "Mild" [19659013]  "Warm"   "Balmy"   "Hot"   "Sweltering"   "Scorching" [19659014]} ; 

     private   readonly  ILogger  < WeatherForecastController >  _logger ; 

     public   WeatherForecastController   ILogger  < WeatherForecastController >  logger ) 
     {
        _logger  =  logger ; 
    } 

     [ HttpGet ] 
     public  IEnumerable  < WeatherForecast > [19659012] Get  () 
     {
         var  rng  =   new   Random  () ; 
         return  Enumerable .  Range  ( 1   5 ) .  Sélectionnez  ( index  = >   nouveau   WeatherForecast 
         {
            Date  =  DateHeure .  Now .  AddDays  ( index ) 
            TemperatureC  =  rng .  Next  ( -  20   55 ) 
            Résumé  =  Résumés  [ rng .  Suivant  ( Résumés .  Longueur ) ] [19659041]} ) 
        .  ToArray  () ; 
    } 
} 

Ceci a les bases avec lesquelles nous pouvons travailler pour comprendre comment la réponse est structurée en termes de format et de code d'état.

Lorsque nous configurons ASP.NET Core avec services.AddControllers cela ajoute les OutputFormatters intégrés, qui sont utilisés pour écrire un objet dans le flux de sortie:

  • Microsoft.AspNetCore.Mvc.Formatters.HttpNoContentOutputFormatter
  • Microsoft.AspNetCore.Mvatterc.Formatters.StringOutFput
  • ] Microsoft.AspNetCore.Mvc.Formatters.StreamOutputFormatter
  • Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter

Ces formateurs de sortie permettent à une action de renvoyer n'importe quelle valeur de retour d'objet. Le formateur est sélectionné ici par le biais du processus appelé négociation de contenu qui se produit lorsque le client spécifie un en-tête Accept.

Regardons cela avec un exemple. Avec la modification ci-dessous, nous ajouterons le formateur de sortie XML à la liste des formateurs pris en charge:

 public   void   ConfigureServices  ( IServiceCollection services ) 
 {
    services .  AddControllers  () .  AddXmlSerializerFormatters  () ; 
} 

Maintenant, nous verrons que la réponse sera écrite en XML lorsque nous spécifierons que nous voulons recevoir le corps de la réponse en XML via l'en-tête Accept:

 curl -v -H "Accept: application / xml" http : // localhost: 5000 / WeatherForecast
* Essayer :: 1 ...
* TCP_NODELAY défini
* Connecté au port 5000 localhost (:: 1) (# 0)
> GET / WeatherForecast HTTP / 1.1
> Hôte: localhost: 5000
> Agent utilisateur: curl / 7.54.0
> Accepter: application / xml
>
<HTTP / 1.1 200 OK
<Date: lun, 13 janvier 2020 21:06:32 GMT
<Type de contenu: application / xml; jeu de caractères = utf-8
<Serveur: Kestrel
<Content-Longueur: 829
<
* La connexion n ° 0 à l'hôte localhost est restée intacte
 2020-01-14T21: 06: 32.786281 + 00: 00  3  Chaud  2020-01-15T21: 06: 32.794902 + 00: 00  36  Doux  ] 2020-01-16T21: 06: 32.794907 + 00: 00  -14  Scorching  2020-01-17T21: 06: 32.794908 + 00: 00  5  Chilly  2020-01-18T21: 06: 32.794908 + 00: 00  -13  Torride   

La réponse sera au format JSON lorsque nous spécifions l'en-tête Accept comme application / json:

 curl -v -H "Accept: application / json" http: // localhost: 5000 / WeatherForecast
* Essayer :: 1 ...
* TCP_NODELAY défini
* Connecté au port 5000 localhost (:: 1) (# 0)
> GET / WeatherForecast HTTP / 1.1
> Hôte: localhost: 5000
> User-Agent: curl / 7.54.0
> Accepter: application / json
>
<HTTP / 1.1 200 OK
<Date: Lun, 13 janvier 2020 21:09:05 GMT
<Type de contenu: application / json; jeu de caractères = utf-8
<Serveur: Kestrel
<Transfert-Encodage: fragmenté
<
* La connexion n ° 0 à l'hôte localhost est restée intacte
[{"date":"2020-01-14T21:09:05.635107+00:00","temperatureC":4,"temperatureF":39,"summary":"Hot"},{"date":"2020-01-15T21:09:05.635279+00:00","temperatureC":-8,"temperatureF":18,"summary":"Scorching"},{"date":"2020-01-16T21:09:05.635281+00:00","temperatureC":42,"temperatureF":107,"summary":"Balmy"},{"date":"2020-01-17T21:09:05.635281+00:00","temperatureC":27,"temperatureF":80,"summary":"Chilly"},{"date":"2020-01-18T21:09:05.635282+00:00","temperatureC":44,"temperatureF":111,"summary":"Warm"}]%

En plus de renvoyer des POCO (Plain Old CLR Objects) et de laisser la négociation de contenu décider quel formateur de sortie choisir, vous pouvez également renvoyer un IActionResult qui définit un contrat qui représente le résultat d'une méthode d'action , à partir de l'action du contrôleur qui peut vous permettre d'avoir un contrôle direct sur le type de retour. Par exemple, l'implémentation d'aide intégrée IActionResult JsonResult renvoie des données au format JSON, quel que soit l'en-tête Accept.

 [ HttpGet ] 
 public  IActionResult  Get  () 
 {
     var  rng  =   new   Random  () ; 
     var  result  =  Enumerable .  Range  ( 1   5 ) .  Sélectionnez  ] ( index  = >   nouveau   WeatherForecast 
     {
        Date  =  DateHeure .  Now .  AddDays  ( index ) 
        TemperatureC  =  rng .  Next  ( -  20   55 ) 
        Résumé  =  Résumés  [ rng .  Suivant  ( Résumés .  Longueur ) ] [19659014]} ) 
    .  ToArray  () ; 

     return   new   JsonResult  ( result  ) ; 
} 
 curl -v -H "Accepter: application / xml" http: // localhost: 5000 / WeatherForecast
* Essayer :: 1 ...
* TCP_NODELAY défini
* Connecté au port 5000 localhost (:: 1) (# 0)
> GET / WeatherForecast HTTP / 1.1
> Hôte: localhost: 5000
> User-Agent: curl / 7.54.0
> Accepter: application / xml
>
<HTTP / 1.1 200 OK
<Date: lun, 13 janvier 2020 21:18:39 GMT
<Type de contenu: application / json; jeu de caractères = utf-8
<Serveur: Kestrel
<Transfert-Encodage: fragmenté
<
* La connexion n ° 0 à l'hôte localhost est restée intacte
[{"date":"2020-01-14T21:18:40.678848+00:00","temperatureC":12,"temperatureF":53,"summary":"Scorching"},{"date":"2020-01-15T21:18:40.685278+00:00","temperatureC":23,"temperatureF":73,"summary":"Chilly"},{"date":"2020-01-16T21:18:40.685283+00:00","temperatureC":24,"temperatureF":75,"summary":"Cool"},{"date":"2020-01-17T21:18:40.685284+00:00","temperatureC":-10,"temperatureF":15,"summary":"Hot"},{"date":"2020-01-18T21:18:40.685284+00:00","temperatureC":-5,"temperatureF":24,"summary":"Bracing"}]%

Modification du code d’état de réponse

Voyons maintenant comment nous pouvons modifier le code d’état de réponse. Avec tous les cas que nous avons mentionnés ci-dessus, nous pouvons simplement définir Response.StatusCode juste avant de renvoyer le résultat au code de statut approprié avec lequel nous voulons répondre:

 [ HttpGet ] 
 public  IActionResult  Get  () 
 {
     var  rng  =   new   Random  ( ]) ; 
     var  result  =  Enumerable .  Range  ( 1   5 ) .  Sélectionnez  ( index  = >   new   WeatherForecast 
     {
        Date  =  DateHeure .  Now .  AddDays  ( index ) 
        TemperatureC  =  rng .  Next  ( -  20   55 ) 
        Résumé  =  Résumés  [ rng .  Suivant  ( Résumés .  Longueur ) ] [19659014]} ) 
    .  ToArray  () ; 

    Réponse .  StatusCode  =  StatusCodes .  Status400BadRequest ; 
     return   new   JsonResult  ( result ) ; 
} 

Vous pouvez voir dans l'exemple de requête ci-dessous que nous récupérons la réponse avec le code d'état 400:

 curl -v -H "Accept: application / json" http: // localhost: 5000 / WeatherForecast
* Essayer :: 1 ...
* TCP_NODELAY défini
* Connecté au port 5000 localhost (:: 1) (# 0)
> GET / WeatherForecast HTTP / 1.1
> Hôte: localhost: 5000
> Agent utilisateur: curl / 7.54.0
> Accepter: application / json
>
<HTTP / 1.1 400 Mauvaise requête
<Date: lun 13 janvier 2020 21:34:53 GMT
<Type de contenu: application / json; jeu de caractères = utf-8
<Serveur: Kestrel
<Transfert-Encodage: fragmenté
<
* La connexion n ° 0 à l'hôte localhost est restée intacte
[{"date":"2020-01-14T21:34:54.415857+00:00","temperatureC":21,"temperatureF":69,"summary":"Sweltering"},{"date":"2020-01-15T21:34:54.4239+00:00","temperatureC":-6,"temperatureF":22,"summary":"Freezing"},{"date":"2020-01-16T21:34:54.423907+00:00","temperatureC":9,"temperatureF":48,"summary":"Mild"},{"date":"2020-01-17T21:34:54.423907+00:00","temperatureC":51,"temperatureF":123,"summary":"Freezing"},{"date":"2020-01-18T21:34:54.423908+00:00","temperatureC":49,"temperatureF":120,"summary":"Hot"}]%

En plus de cette manière simple de définir le code d'état, nous avons également des méthodes d'assistance sur l'objet ControllerBase, ce qui nous donne la possibilité de façonner une réponse. Par exemple, la méthode Conflict crée un ConflictObjectResult qui produit une réponse Status409Conflict .

 [ HttpGet ] 
 public  IActionResult  Get  () 
 {
     var  rng  =   new   Random  ()  ; 
     var  result  =  Enumerable .  Range  ( 1   5 ) . [19659025] Sélectionnez  ( index  = >   new   WeatherForecast 
     {
        Date  =  DateHeure .  Now .  AddDays  ( index ) 
        TemperatureC  =  rng .  Next  ( -  20   55 ) 
        Résumé  =  Résumés  [ rng .  Suivant  ( Résumés .  Longueur ) ] [19659014]} ) 
    .  ToArray  () ; 

     return   Conflict  ( result )  ; 
} 
 curl -v -H "Accepter: application / json" http: // localhost: 5000 / WeatherForecast
* Essayer :: 1 ...
* TCP_NODELAY défini
* Connecté au port 5000 localhost (:: 1) (# 0)
> GET / WeatherForecast HTTP / 1.1
> Hôte: localhost: 5000
> User-Agent: curl / 7.54.0
> Accepter: application / json
>
<HTTP / 1.1 409 Conflit
<Date: lun, 13 janvier 2020 21:38:03 GMT
<Type de contenu: application / json; jeu de caractères = utf-8
<Serveur: Kestrel
<Transfert-Encodage: fragmenté
<
* La connexion n ° 0 à l'hôte localhost est restée intacte
[{"date":"2020-01-14T21:38:04.665259+00:00","temperatureC":-19,"temperatureF":-2,"summary":"Chilly"},{"date":"2020-01-15T21:38:04.673328+00:00","temperatureC":47,"temperatureF":116,"summary":"Bracing"},{"date":"2020-01-16T21:38:04.673334+00:00","temperatureC":28,"temperatureF":82,"summary":"Chilly"},{"date":"2020-01-17T21:38:04.673335+00:00","temperatureC":17,"temperatureF":62,"summary":"Warm"},{"date":"2020-01-18T21:38:04.673335+00:00","temperatureC":49,"temperatureF":120,"summary":"Bracing"}]%

Dans ce cas, peu importe ce que nous avons défini Response.StatusCode dans l'action, il serait remplacé par la méthode d'assistance Conflict .





Source link