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?
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.
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();
}
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.
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();
}
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");
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.
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}");
...
}
}
request.Headers.FirstOrDefault( x => x.Key == "MyCustomID" ).Value?.FirstOrDefault()
variante moderne :)
Solution en une ligne
var id = request.Headers.GetValues("MyCustomID").FirstOrDefault();