web-dev-qa-db-fra.com

Comment extraire la valeur d'en-tête personnalisé dans le gestionnaire de messages de l'API Web?

J'ai actuellement un gestionnaire de messages dans mon service API Web qui remplace "SendAsync" comme suit:

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
  //implementation
}

Dans ce code, je dois inspecter une valeur d'en-tête de demande ajoutée personnalisée nommée MyCustomID. Le problème est quand je fais ce qui suit:

if (request.Headers.Contains("MyCustomID"))  //OK
    var id = request.Headers["MyCustomID"];  //build error - not OK

...Je reçois le message d'erreur suivant:

Impossible d'appliquer l'indexation avec [] à une expression de type 'System.Net.Http.Headers.HttpRequestHeaders'

Comment accéder à un en-tête de requête personnalisé unique via l'instance HttpRequestMessage ( Documentation MSDN ) transmise à cette méthode remplacée?

129
atconway

Essayez quelque chose comme ça:

IEnumerable<string> headerValues = request.Headers.GetValues("MyCustomID");
var id = headerValues.FirstOrDefault();

Il existe également une méthode TryGetValues ​​sur les en-têtes que vous pouvez utiliser si vous n'êtes pas toujours assuré d'avoir accès à l'en-tête.

225
Youssef Moussaoui

La ligne en dessous de throws exception si la clé n'existe pas. 

IEnumerable<string> headerValues = request.Headers.GetValues("MyCustomID");

Solution de contournement :

Inclure System.Linq;

IEnumerable<string> headerValues;
var userId = string.Empty;

     if (request.Headers.TryGetValues("MyCustomID", out headerValues))
     {
         userId = headerValues.FirstOrDefault();
     }           
30
SharpCoder

Pour approfondir la réponse de Youssef, j’ai écrit cette méthode basée sur les préoccupations de Drew concernant l’en-tête inexistant, car j’ai rencontré cette situation lors des tests unitaires.

private T GetFirstHeaderValueOrDefault<T>(string headerKey, 
   Func<HttpRequestMessage, string> defaultValue, 
   Func<string,T> valueTransform)
    {
        IEnumerable<string> headerValues;
        HttpRequestMessage message = Request ?? new HttpRequestMessage();
        if (!message.Headers.TryGetValues(headerKey, out headerValues))
            return valueTransform(defaultValue(message));
        string firstHeaderValue = headerValues.FirstOrDefault() ?? defaultValue(message);
        return valueTransform(firstHeaderValue);
    }

Voici un exemple d'utilisation:

GetFirstHeaderValueOrDefault("X-MyGuid", h => Guid.NewGuid().ToString(), Guid.Parse);

Consultez également la réponse de @ doguhan-uluca pour une solution plus générale.

16
neontapir

Créer une nouvelle méthode - ' Renvoie une valeur d'en-tête HTTP individuelle ' et appelez cette méthode avec la valeur clé chaque fois que vous devez accéder à plusieurs valeurs clés à partir de HttpRequestMessage.

public static string GetHeader(this HttpRequestMessage request, string key)
        {
            IEnumerable<string> keys = null;
            if (!request.Headers.TryGetValues(key, out keys))
                return null;

            return keys.First();
        }
11
SRI

Pour développer davantage la solution @ neontapir, voici une solution plus générique pouvant s'appliquer à HttpRequestMessage ou à HttpResponseMessage de la même manière et ne nécessitant pas d'expressions ou de fonctions codées à la main.

using System.Net.Http;
using System.Collections.Generic;
using System.Linq;

public static class HttpResponseMessageExtensions
{
    public static T GetFirstHeaderValueOrDefault<T>(
        this HttpResponseMessage response,
        string headerKey)
    {
        var toReturn = default(T);

        IEnumerable<string> headerValues;

        if (response.Content.Headers.TryGetValues(headerKey, out headerValues))
        {
            var valueString = headerValues.FirstOrDefault();
            if (valueString != null)
            {
                return (T)Convert.ChangeType(valueString, typeof(T));
            }
        }

        return toReturn;
    }
}

Exemple d'utilisation:

var myValue = response.GetFirstHeaderValueOrDefault<int>("MyValue");
8
Doguhan Uluca

Pour ASP.Net Core, il existe une solution simple si vous souhaitez utiliser le paramètre directement dans la méthode du contrôleur: utilisez l'annotation [FromHeader].

        public JsonResult SendAsync([FromHeader] string myParam)
        {
        if(myParam == null)  //Param not set in request header
        {
           return null;
        }
        return doSomething();
    }   

Informations supplémentaires: Dans mon cas, le "myParam" devait être une chaîne, int était toujours égal à 0.

3
Reiner

Pour ASP.NET, vous pouvez obtenir l'en-tête directement à partir du paramètre dans la méthode du contrôleur à l'aide de this simple library/package . Il fournit un attribut [FromHeader] comme dans ASP.NET Core :). Par exemple:

    ...
    using RazHeaderAttribute.Attributes;

    [Route("api/{controller}")]
    public class RandomController : ApiController 
    {
        ...
        // GET api/random
        [HttpGet]
        public IEnumerable<string> Get([FromHeader("pages")] int page, [FromHeader] string rows)
        {
            // Print in the debug window to be sure our bound stuff are passed :)
            Debug.WriteLine($"Rows {rows}, Page {page}");
            ...
        }
    }
3
lawrenceagbani
request.Headers.FirstOrDefault( x => x.Key == "MyCustomID" ).Value?.FirstOrDefault()

variante moderne :)

2

Solution en une ligne

var id = request.Headers.GetValues("MyCustomID").FirstOrDefault();
0
Roman Marusyk