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

atc*_*way 143 c# httprequest asp.net-web-api

我目前在我的Web API服务中有一个消息处理程序,它覆盖"SendAsync",如下所示:

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
  //implementation
}
Run Code Online (Sandbox Code Playgroud)

在此代码中,我需要检查名为的自定义添加的请求标头值MyCustomID.问题是当我执行以下操作时:

if (request.Headers.Contains("MyCustomID"))  //OK
    var id = request.Headers["MyCustomID"];  //build error - not OK
Run Code Online (Sandbox Code Playgroud)

...我收到以下错误消息:

无法将带有[]的索引应用于"System.Net.Http.Headers.HttpRequestHeaders"类型的表达式

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

You*_*oui 240

尝试这样的事情:

IEnumerable<string> headerValues = request.Headers.GetValues("MyCustomID");
var id = headerValues.FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)

如果您并不总是保证能够访问标题,那么您可以使用Header上的TryGetValues方法.

  • GetValues的空检查不提供任何值,因为它永远不会返回null.如果标头不存在,您将收到InvalidOperationException.如果请求中可能不存在标头并检查错误响应或尝试/捕获GetValues调用(不推荐),则需要使用TryGetHeaders. (26认同)
  • 为什么不只是`var id = request.Headers.GetValues("MyCustomID").FirstOrDefault();` (15认同)
  • @Drew request.Headers.Single(h => h.Key =="Authorization"); 更少的代码做同样的事情! (4认同)
  • @SaeedNeamati因为标题值不是一对一的.在同一个请求中你可以有`Some-Header:one`然后是`Some-Header:two`.有些语言默默地丢弃"一个"但这是不正确的.它在RFC中,但我现在懒得找到它. (3认同)

Sha*_*der 37

throws exception如果密钥不存在,则在下面一行.

IEnumerable<string> headerValues = request.Headers.GetValues("MyCustomID");
Run Code Online (Sandbox Code Playgroud)

解决方法:

包括System.Linq;

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

     if (request.Headers.TryGetValues("MyCustomID", out headerValues))
     {
         userId = headerValues.FirstOrDefault();
     }           
Run Code Online (Sandbox Code Playgroud)


neo*_*pir 16

为了扩展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);
    }
Run Code Online (Sandbox Code Playgroud)

这是一个示例用法:

GetFirstHeaderValueOrDefault("X-MyGuid", h => Guid.NewGuid().ToString(), Guid.Parse);
Run Code Online (Sandbox Code Playgroud)

另请参阅@ doguhan-uluca的答案以获得更通用的解决方案.


小智 12

创建一个新方法 - " 返回单个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();
        }
Run Code Online (Sandbox Code Playgroud)


Rom*_*syk 10

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

var id = request.Headers.GetValues("MyCustomID").FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)

  • @PrasadKanaparthi那么你应该使用另一个答案,例如/sf/answers/1794817951/。你看到没有任何空检查,那么,什么是“request”是“null”?这也是可能的。或者如果“MyCustomID”是空字符串或不等于“foo”怎么办?这取决于上下文,所以这个答案只是描述了方式,以及您需要自己添加的所有验证和业务逻辑 (2认同)
  • @PrasadKanaparthi,如果标头不存在,您将得到一个 InvalidOperationException,而不是 null (2认同)

Dog*_*uca 8

为了进一步扩展@ 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

样品用法:

var myValue = response.GetFirstHeaderValueOrDefault<int>("MyValue");
Run Code Online (Sandbox Code Playgroud)


law*_*ani 5

对于 ASP.NET,您可以使用这个简单的 library/package直接从控制器方法中的参数获取标头。它提供了一个[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}");
            ...
        }
    }
Run Code Online (Sandbox Code Playgroud)