C# 如何在不发出请求的情况下捕获HttpClient请求

C# 如何在不发出请求的情况下捕获HttpClient请求,c#,.net,.net-core,dotnet-httpclient,C#,.net,.net Core,Dotnet Httpclient,我想生成Http请求的内容,但不是实际发出请求。我只想把它存到磁盘上 我就是这样做的,我不是一个超级粉丝。目前只是登录到xUnit测试记录器。是否有更好的方法记录请求而不实际执行它?我不喜欢的最大一点是,我捕获请求的方法不需要格式化,这可能并非在所有情况下都是正确的 public async void GenerateWithHeader() { using (MultipartFormDataContent content = GenerateMultipartContent())

我想生成Http请求的内容,但不是实际发出请求。我只想把它存到磁盘上

我就是这样做的,我不是一个超级粉丝。目前只是登录到xUnit测试记录器。是否有更好的方法记录请求而不实际执行它?我不喜欢的最大一点是,我捕获请求的方法不需要格式化,这可能并非在所有情况下都是正确的

public async void GenerateWithHeader()
{
    using (MultipartFormDataContent content = GenerateMultipartContent())
    {
        HttpClient c = new HttpClient(new RequestCaptureHandler(new HttpClientHandler(), this.output));
        HttpRequestMessage msg = new HttpRequestMessage(HttpMethod.Post, "http://test.ca");

        //we want xml back
        msg.Headers.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/xml"));

        msg.Content = content;

        try
        {
            await c.SendAsync(msg);
        }
        catch (InvalidOperationException)
        {
            //suppress it.  we don't actually want to make the request
        }
    }
}

public class RequestCaptureHandler : DelegatingHandler
{
    private readonly ITestOutputHelper output;
    public RequestCaptureHandler(HttpMessageHandler innerHandler, ITestOutputHelper output)
        : base(innerHandler)
    {
        this.output = output;
    }

    protected override async System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        //The Request-Line begins with a method token, followed by the Request-URI and the protocol version, and ending with CRLF.The elements are separated by space characters.
        //Request-Line = Method <space> Request-URI <space> HTTP-Version CRLF
        this.output.WriteLine($"{request.Method} {request.RequestUri.ToString()} {request.Version}");

        //Zero or more header (General|Request|Entity) fields followed by CRLF
        foreach (var h in request.Headers)
        {
            this.output.WriteLine($"{h.Key}: {string.Join(' ', h.Value)}");
        }
                
        foreach (var h in request.Content.Headers)
        {
            this.output.WriteLine($"{h.Key}: {string.Join(' ', h.Value)}");
        }

        //An empty line (i.e., a line with nothing preceding the CRLF)  indicating the end of the header fields
        this.output.WriteLine("");

        //Optionally a message-body
        if (request.Content != null)
        {
            this.output.WriteLine(await request.Content.ReadAsStringAsync());
        }

        //Don't actually want to make the request.  This will cause an InvalidOperationException when the SendAsync function of HttpClient is called.
        return null;
    }
}
public异步void GenerateWithHeader()
{
使用(MultipartFormDataContent=GenerateMultipartContent())
{
HttpClient c=newhttpclient(newrequestcapturehandler(newhttpclienthandler(),this.output));
HttpRequestMessage msg=新的HttpRequestMessage(HttpMethod.Post)http://test.ca");
//我们想要回xml
msg.Headers.Accept.Add(新的System.Net.Http.Headers.MediaTypeWithQualityHeaderValue(“应用程序/xml”);
msg.Content=内容;
尝试
{
等待c.SendAsync(msg);
}
捕获(无效操作异常)
{
//抑制它。我们实际上不想提出请求
}
}
}
公共类RequestCaptureHandler:DelegatingHandler
{
私有只读ITestOutputHelper输出;
public RequestCaptureHandler(HttpMessageHandler innerHandler,ITestOutputHelper输出)
:base(innerHandler)
{
这个。输出=输出;
}
受保护的重写异步System.Threading.Tasks.Task SendAsync(HttpRequestMessage请求,System.Threading.CancellationToken CancellationToken)
{
//请求行以方法令牌开始,然后是请求URI和协议版本,最后是CRLF。元素之间用空格字符分隔。
//请求行=方法请求URI HTTP版本CRLF
this.output.WriteLine($“{request.Method}{request.RequestUri.ToString()}{request.Version}”);
//零个或多个标头(常规|请求|实体)字段,后跟CRLF
foreach(request.Headers中的var h)
{
this.output.WriteLine($“{h.Key}:{string.Join('',h.Value)}”);
}
foreach(request.Content.Headers中的var h)
{
this.output.WriteLine($“{h.Key}:{string.Join('',h.Value)}”);
}
//一个空行(即,CRLF前面没有任何内容的行),指示标题字段的结尾
this.output.WriteLine(“”);
//(可选)消息正文
if(request.Content!=null)
{
this.output.WriteLine(wait request.Content.ReadAsStringAsync());
}
//实际上不希望发出请求。这将在调用HttpClient的SendAsync函数时导致InvalidOperationException。
返回null;
}
}

实际上,自己构建它非常简单。http结构有很好的文档记录,实际上只是包含数据的换行符。您只需要一个StringBuilder,使用客户端将增加比您需要的更多的开销。此外,客户机和请求对象不打算以这种方式使用,尽管请求对象可能会以您想要的方式序列化。如果您只想保存请求而不想执行,为什么不存储HttpRequestMessage对象本身呢?。顺便说一句,值得注意的是,同一个HttpRequestMessage实例不能多次发送。如果您的目的只是为了调试目的而检查请求,我建议使用Fiddler并将应用程序配置为将其用作代理。如果没有,您可以实现另一个web应用程序,并将此应用程序配置为使用另一个作为代理,然后您可以使用新的web应用程序来检查原始请求。@Bakurits-HttpRequestMessage不包括请求行或请求头。实际上,自己构建它非常简单。http结构有很好的文档记录,实际上只是包含数据的换行符。您只需要一个StringBuilder,使用客户端将增加比您需要的更多的开销。此外,客户机和请求对象不打算以这种方式使用,尽管请求对象可能会以您想要的方式序列化。如果您只想保存请求而不想执行,为什么不存储HttpRequestMessage对象本身呢?。顺便说一句,值得注意的是,同一个HttpRequestMessage实例不能多次发送。如果您的目的只是为了调试目的而检查请求,我建议使用Fiddler并将应用程序配置为将其用作代理。如果没有,您可以实现另一个web应用程序,并将此应用程序配置为使用另一个作为代理,然后您可以使用新的web应用程序检查原始请求。@Bakurits-HttpRequestMessage不包括请求行或请求头。