如何在Web API消息处理程序中提取自定义头值
本文关键字:提取 自定义 程序 消息处理 Web API | 更新日期: 2023-09-27 18:00:06
我目前在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.Headers.HttpRequestHeaders"
如何通过传递到此重写方法中的HttpRequestMessage
(MSDN Documentation)实例访问单个自定义请求标头?
试试这样的东西:
IEnumerable<string> headerValues = request.Headers.GetValues("MyCustomID");
var id = headerValues.FirstOrDefault();
如果不能始终保证您有权访问header,则可以在header上使用TryGetValues方法。
throws exception
下方的行(如果键不存在)。
IEnumerable<string> headerValues = request.Headers.GetValues("MyCustomID");
使用TryGetValues的安全解决方案:
包括System.Linq;
IEnumerable<string> headerValues;
var userId = string.Empty;
if (request.Headers.TryGetValues("MyCustomID", out headerValues))
{
userId = headerValues.FirstOrDefault();
}
为了扩展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的答案,找到一个更通用的解决方案。
创建一个新方法-'返回一个单独的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();
}
为了进一步扩展@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");
单行解决方案(假设标头存在)
var id = request.Headers.GetValues("MyCustomID").FirstOrDefault();
对于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}");
...
}
}
对于ASP.Net Core,如果要在控制器方法中直接使用param,有一个简单的解决方案:使用[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()
现代变体:)
另一种方法
string customHeader = string.Empty;
if (Request.Headers.TryGetValue("x-date", out var xdateValue))
{
customHeader = xdateValue;
};
这听起来可能很明显,但请确保读取标头的控制器是请求通过的第一个控制器。
我有两个WebAPI项目在相互交流。第一个是代理,第二个包含逻辑。愚蠢的是,我试着在第二个控制器中读取自定义标头,而不是第一个。
var token = string.Empty;
if (Request.Headers.TryGetValue("MyKey", out headerValues))
{
token = headerValues.FirstOrDefault();
}
var headers = Request.Headers;
string token = headers.Contains("token") ? headers.GetValues("token").FirstOrDefault() ?? "" : "";