【问题标题】:Convert Microsoft.AspNetCore.Http.HttpRequest to HttpRequestMessage将 Microsoft.AspNetCore.Http.HttpRequest 转换为 HttpRequestMessage
【发布时间】:2018-01-27 07:17:15
【问题描述】:

我需要将 Microsoft.AspNetCore.Http.HttpRequest 从 AspNetCore 上下文转换为 HttpRequestMessage 以传递给 HttpClient。有没有一种简单的方法可以实现这一目标?或者任何实现这一点的提示都会非常有帮助。

更新 我想将请求转换为消息,但我想更改目标 url,我只想将请求重定向到另一个服务器。

【问题讨论】:

  • 这似乎是一个奇怪的问题。你能解释一下你想要完成什么吗?在将当前请求传递给另一个 api 之前,是否需要从当前请求中提取一些信息?
  • 问题是我们在应用程序中托管了 AspNetCore 中的 TestServer,我们希望将对应用程序发出的一些请求重定向到内部 TestServer。要实现这一点,我们发现的唯一方法是实现一个中间件,从 Context 获取 Request 并将其从 TestServer 传递给 HttpClient 代理。我们还想实现相反的效果:将 HttpRespondeMessage 转换为 HttpResponse。
  • 这并没有多大意义。您在 ASP.NET Core 应用程序上收到的 HttpRequest 是针对该特定主机的。如果您要使用 HttpClient 请求相同的对象,您只需再次访问您自己的应用程序。你到底想达到什么目的?你想将数据传递到不同的服务器,或者你想做什么?
  • @poke 没错,我想发出同样的请求,但是是的,改变目标 url,只需将相同的请求传递给另一个目标,就像某种方式的代理一样。
  • 我在 .NET 4.5 之间也遇到过类似的问题。 HttpRequestMessage 和 HttpWebRequest 以及我使用的方法是将对象之间的所有属性连接起来,理论上应该可以正常工作。

标签: c# asp.net-core request


【解决方案1】:

试试 Web API 兼容性 Shim

HttpRequestMessageFeature hreqmf = new HttpRequestMessageFeature(httpRequest.HttpContext);
HttpRequestMessage httpRequestMessage = hreqmf.HttpRequestMessage;

或者您可以从 Microsoft.AspNetCore.Proxy

中获得灵感

These extensions 转 httpContext 可能会派上用场。

【讨论】:

  • 对于那些只想用最少的代码立即工作的人来说,就是这样。很遗憾您没有得到公认的答案。
【解决方案2】:

IHttpRequestMessageFeatureMicrosoft.AspNetCore.Proxy 均已停产。自 ASP.NET Core 3.0 起,IHttpRequestMessageFeature 已被删除。

Microsoft 现在有一个基于 ASP.NET Core 基础架构的新反向代理 nuget 包 Microsoft.ReverseProxy。根据他们的文档,直接代理场景的IHttpProxy 可以:

充当传入 AspNetCore 和传出 System.Net.Http 请求之间的核心代理适配器。它处理从HttpContext 创建HttpRequestMessage、发送它并转发响应的机制。

这里是an example

【讨论】:

【解决方案3】:

我最终这样做了:

public static class RequestTranscriptHelpers
{
    public static HttpRequestMessage ToHttpRequestMessage(this HttpRequest req)
        => new HttpRequestMessage()
            .SetMethod(req)
            .SetAbsoluteUri(req)
            .SetHeaders(req)
            .SetContent(req)
            .SetContentType(req);

    private static HttpRequestMessage SetAbsoluteUri(this HttpRequestMessage msg, HttpRequest req)
        => msg.Set(m => m.RequestUri = new UriBuilder
        {
            Scheme = req.Scheme,
            Host = req.Host.Host,
            Port = req.Host.Port.Value,
            Path = req.PathBase.Add(req.Path),
            Query = req.QueryString.ToString()
        }.Uri);

    private static HttpRequestMessage SetMethod(this HttpRequestMessage msg, HttpRequest req)
        => msg.Set(m => m.Method = new HttpMethod(req.Method));

    private static HttpRequestMessage SetHeaders(this HttpRequestMessage msg, HttpRequest req)
        => req.Headers.Aggregate(msg, (acc, h) => acc.Set(m => m.Headers.TryAddWithoutValidation(h.Key, h.Value.AsEnumerable())));

    private static HttpRequestMessage SetContent(this HttpRequestMessage msg, HttpRequest req)
        => msg.Set(m => m.Content = new StreamContent(req.Body));

    private static HttpRequestMessage SetContentType(this HttpRequestMessage msg, HttpRequest req)
        => msg.Set(m => m.Content.Headers.Add("Content-Type", req.ContentType), applyIf: req.Headers.ContainsKey("Content-Type"));

    private static HttpRequestMessage Set(this HttpRequestMessage msg, Action<HttpRequestMessage> config, bool applyIf = true)
    {
        if (applyIf)
        {
            config.Invoke(msg);
        }

        return msg;
    }
}



  public static class ResponseTranscriptHelpers
    {
        public static async Task FromHttpResponseMessage(this HttpResponse resp, HttpResponseMessage msg)
        {
            resp.SetStatusCode(msg)
                .SetHeaders(msg)
                .SetContentType(msg);

            await resp.SetBodyAsync(msg);
        }

        private static HttpResponse SetStatusCode(this HttpResponse resp, HttpResponseMessage msg)
            => resp.Set(r => r.StatusCode = (int)msg.StatusCode);

        private static HttpResponse SetHeaders(this HttpResponse resp, HttpResponseMessage msg)
            => msg.Headers.Aggregate(resp, (acc, h) => acc.Set(r => r.Headers[h.Key] = new StringValues(h.Value.ToArray())));

        private static async Task<HttpResponse> SetBodyAsync(this HttpResponse resp, HttpResponseMessage msg)
        {
            using (var stream = await msg.Content.ReadAsStreamAsync())
            using (var reader = new StreamReader(stream))
            {
                var content = await reader.ReadToEndAsync();

                return resp.Set(async r => await r.WriteAsync(content));
            }
        }

        private static HttpResponse SetContentType(this HttpResponse resp, HttpResponseMessage msg)
            => resp.Set(r => r.ContentType = msg.Content.Headers.GetValues("Content-Type").Single(), applyIf: msg.Content.Headers.Contains("Content-Type"));

        private static HttpResponse Set(this HttpResponse msg, Action<HttpResponse> config, bool applyIf = true)
        {
            if (applyIf)
            {
                config.Invoke(msg);
            }

            return msg;
        }
    }

自从我首先找到此解决方案以来,我还没有尝试过 @Strenkor En'Triel 响应,但我会尝试一下。

【讨论】:

  • 我觉得这个sn-p的编码器试图尽可能地混淆代码!我从未见过以如此复杂的方式编写的简单代码。请检查 Microsoft 的其他人如何简单地编写它:github.com/aspnet/Proxy/blob/master/src/…
  • 作者所做的是将代码分解,以便它可以以多种方式使用。在我看来,这个代码很漂亮,读起来也很好。
猜你喜欢
  • 2013-04-22
  • 2013-07-13
  • 1970-01-01
  • 1970-01-01
  • 2020-12-22
  • 1970-01-01
  • 1970-01-01
  • 2018-09-14
  • 2015-03-23
相关资源
最近更新 更多