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

时间:2013-02-19 21:08:39

标签: c# asp.net-web-api httprequest

我目前在我的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'

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

11 个答案:

答案 0 :(得分:230)

尝试这样的事情:

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

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

答案 1 :(得分:32)

如果密钥不存在,则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();
     }           

答案 2 :(得分: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);
    }

以下是一个示例用法:

GetFirstHeaderValueOrDefault("X-MyGuid", h => Guid.NewGuid().ToString(), Guid.Parse);

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

答案 3 :(得分:11)

创建新方法 - &#39; 返回单个HTTP标头值&#39;当您需要从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();
        }

答案 4 :(得分:8)

为了进一步扩展@ neontapir的解决方案,这里有一个更通用的解决方案,可以同样适用于HttpRequestMessage或HttpResponseMessage,不需要手工编码的表达式或函数。

[:ONE,:TWO,:THREE,:FOUR]

样本用法:

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;
    }
}

答案 5 :(得分:4)

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

答案 6 :(得分:3)

对于ASP.NET,您可以使用this simple 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}");
            ...
        }
    }

答案 7 :(得分:2)

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

现代变体:)

答案 8 :(得分:1)

一线解决方案

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

答案 9 :(得分:0)

这听起来似乎很明显,但是请确保您要在其中读取标题的Controller是请求通过的 first Controller。

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

答案 10 :(得分:0)

var keysToRemove = new List<string>();

foreach (var key in dict.Keys)
{
    if (key.Length < word.Length) continue;

    var tmpKey = key;
    var tmpWord = word;

    foreach (var chr in word)
    {
        var keyIndex = tmpKey.IndexOf(chr);
        if (keyIndex < 0) break;
        tmpKey = tmpKey.Remove(keyIndex, 1);
        tmpWord = tmpWord.Remove(0, 1);
    }

    if (tmpWord.Length == 0) keysToRemove.Add(key);
}

foreach (var keyToRemove in keysToRemove)
{
    dict.Remove(keyToRemove);
}