如何在 Web API 消息处理程序中提取自定义头值?

我目前在我的 Web 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.Header. HttpRequestHeader’

如何通过传递给这个重写方法的 HttpRequestMessage(MSDN 文档)实例访问 单身自定义请求头?

260957 次浏览

试试这样:

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

在 Header 上还有一个 试试价值观方法,如果不能保证总是能够访问 Header,那么可以使用它。

为了扩展 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 对更一般性解决方案的回答。

如果键不存在,则在 throws exception下面的行。

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

使用 TryGetValue 的安全解决方案:

包括系统;

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


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

为了进一步扩展这个解决方案,这里有一个更通用的解决方案,它可以同样适用于 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");

创建一个新方法-“ 返回一个单独的 HTTP Header 值”,并在每次需要从 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();
}

对于 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。

request.Headers.FirstOrDefault( x => x.Key == "MyCustomID" ).Value.FirstOrDefault()

现代变体:)

对于 ASP.NET,您可以使用 这个简单的库/包直接从控制器方法中的参数获取标头。它提供了一个 [FromHeader]属性,就像你在 ASP.NET 核心:)。例如:

    ...
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}");
...
}
}

一行解决方案(假设标头存在)

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

这可能听起来很明显,但是请确保读取头信息的控制器是请求通过的 第一控制器。

我有两个相互通信的 WebAPI 项目。第一个是代理,第二个包含逻辑。愚蠢的我,我尝试在第二个控制器中读取自定义头,而不是第一个。

var token = string.Empty;
if (Request.Headers.TryGetValue("MyKey",  out headerValues))
{
token = headerValues.FirstOrDefault();
}

另一种方法

 string customHeader = string.Empty;
if (Request.Headers.TryGetValue("x-date", out var xdateValue))
{
customHeader = xdateValue;
};
var headers = Request.Headers;
string token = headers.Contains("token") ? headers.GetValues("token").FirstOrDefault() ?? "" : "";