POST数据后HttpClient.PostAsync HttpContent参数值为null

atc*_*way 5 c# http-post dotnet-httpclient

我有一个循环遍历一个简短的列表,URIs需要发送每个相同的内容.它HttpContent驻留在传递给调用的变量中PostAsync.我遇到的问题是第一次调用工作正常,但所有后续调用都失败,因为请求内容是null在第一次调用完成之后.

我认为我对PostAsync封面下的电话的理解可能缺乏对象的一些低级细节,而且它的生命周期(或缺乏),所以希望有人可以为我阐明它.

代码如下:

HttpResponseMessage httpResponseMessage = httpClient.PostAsync(destionationUri, messageContent).Result;
Run Code Online (Sandbox Code Playgroud)

有问题的变量是从中衍生出来messageContent的类型.我想一些将值复制到一个新的独立位置以供重用的粗暴方法可能会起作用,但我希望了解为什么会发生这种情况以及允许内容在循环期间保持不变的正确方法.MultipartFormDataContentHttpContent

有谁知道我如何解决这个问题,并在循环上面的代码时,messageContent值将在迭代之间持续存在?

编辑:我继续和重构的代码重建MultipartFormDataContent使用之前,每次调用相同的数据从头开始PostAsync使用的实例HttpClient.重建HtppContent实际工作的呼吁; 该值不为null.但是,当我现在去进行后续调用PostAsync和访问时,.Result我收到以下错误:

将内容复制到流时出错.无法访问封闭的Stream.

编辑2:在检查第二次调用我的方法MultipartFormDataContent从头开始重建对象时,我注意到我的附件属性在检查它的ContentStream属性(Mail.MailMessage对象)时声明如下:

attachment.ContentStream.Position抛出了类型的异常 System.ObjectDisposedException

所有属性都表明ContentStream无法再读取它,因为它已被丢弃.呼吁PostAsync().Result显然是处理流并且可能是根本问题.但是我仍然无法找到可行的解决方案.

Dar*_*ler 8

您可以通过创建一个允许重复使用内容类的新"包装器"HttpContent类来使解决方案更加整洁.发送内容时,HttpClient会自动处理任何请求内容,"以防万一".这不是你的理由.幸运的是,Dispose(bool)方法是虚拟的,因此您可以覆盖派生类中的dispose行为.

 public class ReusableContent : HttpContent
    {
        private readonly HttpContent _innerContent;

        public ReusableContent(HttpContent innerContent)
        {
            _innerContent = innerContent;
        }

        protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context)
        {
            await _innerContent.CopyToAsync(stream);
        }

        protected override bool TryComputeLength(out long length)
        {
            length = -1;
            return false;
        }

        protected override void Dispose(bool disposing)
        {
            // Don't call base dispose
            //base.Dispose(disposing);
        }
    }
Run Code Online (Sandbox Code Playgroud)

一旦你有了这个课程,就可以像这样使用它,

    [Fact]
    public async Task Sending_same_content_multiple_times()
    {
        var client = new HttpClient { BaseAddress = _BaseAddress };


        var stream = new MemoryStream();
        var sw = new StreamWriter(stream);
        sw.Write("This is a stream");
        sw.Flush();
        stream.Position = 0;

        var multipart = new MultipartContent
        {
            new StringContent("This string will be sent repeatedly"),
            new FormUrlEncodedContent(new[] {new KeyValuePair<string, string>("foo", "bar"),}),
            new StreamContent(stream)
        };

        var content = new ReusableContent(multipart);

        for (int i = 0; i < 10; i++)
        {
            var response = await client.PostAsync("devnull", content);
            response.EnsureSuccessStatusCode();
        }

    }
Run Code Online (Sandbox Code Playgroud)

如果您确实使用此功能,请确保不使用实际需要处理但未手动处理的内容.