Как извлечь значение настраиваемого заголовка в обработчик сообщений Web API?
В настоящее время у меня есть обработчик сообщений в моей службе веб-API, который переопределяет "SendAsync" следующим образом:
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
//implementation
}
Внутри этого кода мне нужно проверить значение заголовка пользовательского добавленного запроса с именем MyCustomID
. Проблема в том, что я делаю следующее:
if (request.Headers.Contains("MyCustomID")) //OK
var id = request.Headers["MyCustomID"]; //build error - not OK
... Появляется следующее сообщение об ошибке:
Невозможно применить индексирование с [] к выражению типа 'System.Net.Http.Headers.HttpRequestHeaders'
Как я могу получить доступ к отдельному заголовку пользовательского запроса с помощью HttpRequestMessage
(Документация MSDN), который передается в этот переопределенный метод?
Ответы
Ответ 1
Попробуйте что-то вроде этого:
IEnumerable<string> headerValues = request.Headers.GetValues("MyCustomID");
var id = headerValues.FirstOrDefault();
Также существует метод TryGetValues в заголовках, которые вы можете использовать, если у вас не всегда гарантирован доступ к заголовку.
Ответ 2
Строка ниже throws exception
, если ключ не существует.
IEnumerable<string> headerValues = request.Headers.GetValues("MyCustomID");
Работать вокруг:
Включить System.Linq;
IEnumerable<string> headerValues;
var userId = string.Empty;
if (request.Headers.TryGetValues("MyCustomID", out headerValues))
{
userId = headerValues.FirstOrDefault();
}
Ответ 3
Чтобы расширить ответ на Youssef, я написал этот метод, основанный на Drew, о том, что заголовок не существует, потому что я столкнулся с этой ситуацией во время модульного тестирования.
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);
}
Здесь пример использования:
GetFirstHeaderValueOrDefault("X-MyGuid", h => Guid.NewGuid().ToString(), Guid.Parse);
Также посмотрите на ответ @doguhan-uluca для более общего решения.
Ответ 4
Создайте новый метод - Возвращает индивидуальное значение заголовка HTTP "и каждый раз вызывайте этот метод с ключевым значением, когда вам нужно получить доступ к нескольким ключевым значениям из 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();
}
Ответ 5
Для дальнейшего расширения решения @neontapir, здесь более общее решение, которое может применяться к HttpRequestMessage или HttpResponseMessage одинаково и не требует ручных кодированных выражений или функций.
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;
}
}
Использование образца:
var myValue = response.GetFirstHeaderValueOrDefault<int>("MyValue");
Ответ 6
Для ASP.Net Core существует простое решение, если вы хотите использовать параметр непосредственно в методе контроллера: используйте аннотацию [FromHeader].
public JsonResult SendAsync([FromHeader] string myParam)
{
if(myParam == null) //Param not set in request header
{
return null;
}
return doSomething();
}
Дополнительная информация: В моем случае "myParam" должен был быть строкой, int всегда 0.
Ответ 7
request.Headers.FirstOrDefault( x => x.Key == "MyCustomID" ).Value?.FirstOrDefault()
современный вариант:)
Ответ 8
Для ASP.NET вы можете получить заголовок непосредственно из параметра в методе контроллера, используя эту простую библиотеку/пакет. Он предоставляет атрибут [FromHeader]
, как и в ASP.NET Core:). Например:
...
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}");
...
}
}