我目前在我的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)实例访问单个自定义请求标头?
答案 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);
}