【问题标题】:How do I compare headers from HttpContext.Request/Response with those of HttpRequestMessage.Request/Response?如何将 HttpContext.Request/Response 的标头与 HttpRequestMessage.Request/Response 的标头进行比较?
【发布时间】:2022-11-22 04:01:20
【问题描述】:

我对 HttpContext 类使用与 HttpRequestMessageHttpResponseMessage 不同的请求和响应类型感到恼火。 HttpContext 类使用 IHeaderDictionary 作为标头,而其他类使用 HttpRequestHeadersHttpResponseHeaders 作为标头。 (两者均源自HttpHeaders。)
我的问题是我正在开发一个 Web API,它需要从上下文中提取标头并向前传递这些标头,同时使用 HttpClient.SendAsync(...) 调用另一个站点。 (是的,网站!不是其他服务!)
我想要的是一个简单的函数,可以将标头从上下文请求复制到新请求。在执行请求后我想使用相同的功能将响应中的标头复制到我的上下文响应中。这无法完成,因为标题是不同的类型。

涉及的类型有:
interface IHeaderDictionary : IDictionary<string, StringValues>{}
class HttpHeaders : IEnumerable<KeyValuePair<string, IEnumerable<string>>>
因此,挑战在于我们有一个带有 StringValues 值的字典与一个带有可枚举 as 值的可枚举对象。比较苹果和梨,基本上...
那我该怎么做单一功能可以将标题从一个列表分配给另一个?

【问题讨论】:

  • 是的,我可以只创建两个函数,但是我在两个函数之间有基本上是复制/粘贴的代码。或者做第三个功能。甚至更多。这暂时解决了它,但我正在将标头复制到标头,这样应该可以更简单地实现!
  • 两种方法有什么问题?您可以创建一个具有内部类型转换和检查的方法,但该方法的签名不是类型安全的。我认为您应该保留两个简单易读的方法,并称其为好。
  • @Kit 两种方法都没有错,只是我最终违反了 DRY 规则。复制这些标头时需要对其进行一些验证和修改。是的,内部类型转换不会很漂亮。但正如我所说,我基本上是将标头复制到标头,所以为什么这么难?

标签: c# http-headers c#-10.0


【解决方案1】:

我能想到的最好的事情是部分 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));
}

此方法假定这两个集合实际上已经存在。如果您必须创建目标集合并返回它,该方法将变得更加复杂,并且您将失去在调用站点推断类型参数的能力。

为了证明代码实际上可以被编译,我创建了一个带有 Copy 变体的控制器,它采用可为 null 的参数。 (这只是为了将所有内容保存在一个地方)。

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

【讨论】:

    猜你喜欢
    • 2014-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多