如何在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
…我收到以下错误信息:
无法将[]的索引应用于types为“System.Net.Http.Headers.HttpRequestHeaders”的expression式
如何通过传入此重写方法的HttpRequestMessage
( MSDN文档 )实例访问单个自定义请求标头?
尝试这样的事情:
IEnumerable<string> headerValues = request.Headers.GetValues("MyCustomID"); var id = headerValues.FirstOrDefault();
如果您不总是保证有权访问标题,则可以使用Headers上的TryGetValues方法。
如果该键不存在,则下面的行将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(); }
为了扩大Youssef的回答,我写了这个方法,这个方法是根据Drew关于头部不存在的问题,因为我在unit testing中遇到了这种情况。
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为更一般的解决scheme的答案。
创build一个新的方法 – 当你需要访问HttpRequestMessage中的多个键值时,每次都返回一个单独的HTTP Header值 ,并用键值调用这个方法。
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的解决scheme,下面是一个更通用的解决scheme,可以同时应用于HttpRequestMessage或HttpResponseMessage,不需要手动编码的expression式或函数。
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");
对于ASP.Net Core,如果想直接在控制器方法中使用param,有一个简单的解决scheme:使用[FromHeader]注释。
public JsonResult SendAsync([FromHeader] string myParam) { if(myParam == null) //Param not set in request header { return null; } return doSomething(); }
附加信息:在我的情况下,“myParam”必须是一个string,int始终是0。
request.Headers.FirstOrDefault( x => x.Key == "MyCustomID" ).Value?.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}"); ... } }