[英]How do I compare headers from HttpContext.Request/Response with those of HttpRequestMessage.Request/Response?
I am annoyed with the HttpContext
class that uses different types for the request and response than HttpRequestMessage
and HttpResponseMessage
.我对
HttpContext
class 使用与HttpRequestMessage
和HttpResponseMessage
不同的请求和响应类型感到恼火。 The HttpContext class uses IHeaderDictionary
for the headers while the other classes use HttpRequestHeaders
and HttpResponseHeaders
for the headers. HttpContext class 使用
IHeaderDictionary
作为标头,而其他类使用HttpRequestHeaders
和HttpResponseHeaders
作为标头。 (Both are derived from HttpHeaders
.) (两者都派生自
HttpHeaders
。)
My problem is that I'm working on a Web API that needs to extract headers from the context and pass these headers onwards while using HttpClient.SendAsync(...)
to call another site.我的问题是我正在处理 Web API 需要从上下文中提取标头并在使用
HttpClient.SendAsync(...)
调用另一个站点时向前传递这些标头。 (Yes, site! Not another service!) (是的,网站!不是其他服务!)
What I want is a simple function that can copy the headers from the context request to the new request.我想要的是一个简单的 function,它可以将标头从上下文请求复制到新请求。 And after the request is executed I want to use the same function to copy the headers from the response into my context response.
在执行请求后,我想使用相同的 function将响应中的标头复制到我的上下文响应中。 This cannot be done because the headers are different types.
这无法完成,因为标题是不同的类型。
The types involved are:涉及的类型有:
interface IHeaderDictionary: IDictionary<string, StringValues>{}
class HttpHeaders: IEnumerable<KeyValuePair<string, IEnumerable<string>>>
So the challenge is that we have a dictionary with a StringValues
value versus an enumerable with an enumerable as value.所以挑战在于我们有一个带有
StringValues
值的字典与一个带有可枚举 as 值的可枚举。 Comparing apples and pears, basically...比较苹果和梨,基本上...
So how do I make a single function that can assign headers from one list to another?那么我如何制作一个可以将标题从一个列表分配给另一个列表的 function呢?
The best thing that I could come up with is partially DRY, and is mostly typesafe.我能想到的最好的事情是部分 DRY,并且大部分是类型安全的。
void Copy<T, U>(IEnumerable<KeyValuePair<string, T>> from, IEnumerable<KeyValuePair<string, U>> to)
where T : IEnumerable<string>
where U : IEnumerable<string>
{
if (to is IHeaderDictionary headerDictionary)
foreach (var x in from)
headerDictionary.Add(x.Key, new StringValues(x.Value.ToArray()));
else
if (to is HttpHeaders httpHeaders)
foreach (var x in from)
httpHeaders.Add(x.Key, new List<string?>(x.Value));
}
This method assumes both collections actually already exist.此方法假定 collections 实际上已经存在。 If you have to create the target collection and return it, the method would get way more complex, and you'd lose the ability to infer the type parameters at the call site.
如果您必须创建目标集合并返回它,该方法将变得更加复杂,并且您将失去在调用站点推断类型参数的能力。
To prove that the code can actually be compiled, I created a controller with a variation of Copy
that takes nullable parameters.为了证明代码实际上可以编译,我创建了一个 controller,它带有一个采用可为空参数的
Copy
变体。 (This is just to keep all of it in a single place). (这只是为了将所有内容保存在一个地方)。
[ApiController]
public class WeatherForecastController : ControllerBase
{
void Copy<T, U>(IEnumerable<KeyValuePair<string, T>>? from, IEnumerable<KeyValuePair<string, U>>? to)
where T : IEnumerable<string>
where U : IEnumerable<string>
{
if (from == null || to == null)
return;
if (to is IHeaderDictionary headerDictionary)
foreach (var x in from)
headerDictionary.Add(x.Key, new StringValues(x.Value.ToArray()));
else
if (to is HttpHeaders httpHeaders)
foreach (var x in from)
httpHeaders.Add(x.Key, new List<string?>(x.Value));
}
public void Test()
{
// in real life, these come from somewhere else and won't be null
HttpRequestHeaders? requestHeaders = null;
HttpRequestHeaders? responseHeaders = null;
// actual types are inferred. yay!
Copy(HttpContext.Request.Headers, requestHeaders);
Copy(requestHeaders, HttpContext.Request.Headers);
Copy(HttpContext.Response.Headers, responseHeaders);
Copy(responseHeaders, HttpContext.Response.Headers);
Copy(requestHeaders, responseHeaders);
Copy(responseHeaders, requestHeaders);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.