【问题标题】:using HttpClient, how can I save a XDocument directly to the request stream?使用 HttpClient,如何将 XDocument 直接保存到请求流中?
【发布时间】:2012-02-11 18:28:34
【问题描述】:

使用 HttpWebRequest,我可以调用 XDocument.Save() 将直接写入请求流:

XDocument doc = ...;
var request = (HttpWebRequest)WebCreate.Create(uri);
request.method = "POST";
Stream requestStream = request.GetRequestStream();
doc.Save(requestStream);

HttpClient 可以做同样的事情吗?直接的方法是

XDocument doc = ...;
Stream stream = new MemoryStream();
doc.Save(stream);
var content = new System.Net.Http.StreamContent(stream);
var client = new HttpClient();
client.Post(uri, content);

但这会在MemoryStream 中创建XDocument另一个副本。

【问题讨论】:

    标签: .net rest httpwebrequest .net-4.5 dotnet-httpclient


    【解决方案1】:

    XDocument.Save() 需要一个可以写入的StreamStreamContent 需要一个可以读取的流。因此,您可以使用两个Streams,其中一个充当另一个的转发器。我认为框架中不存在这种类型,但您可以自己编写一个:

    class ForwardingStream
    {
        private readonly ReaderStream m_reader;
        private readonly WriterStream m_writer;
    
        public ForwardingStream()
        {
            // bounded, so that writing too much data blocks
            var buffers = new BlockingCollection<byte[]>(10);
            m_reader = new ReaderStream(buffers);
            m_writer = new WriterStream(buffers);
        }
    
        private class ReaderStream : Stream
        {
            private readonly BlockingCollection<byte[]> m_buffers;
            private byte[] m_currentBuffer;
            private int m_readFromCurrent;
    
            public ReaderStream(BlockingCollection<byte[]> buffers)
            {
                m_buffers = buffers;
            }
    
            public override void Flush()
            {}
    
            public override long Seek(long offset, SeekOrigin origin)
            {
                throw new NotSupportedException();
            }
    
            public override void SetLength(long value)
            {
                throw new NotSupportedException();
            }
    
            public override int Read(byte[] buffer, int offset, int count)
            {
                if (m_currentBuffer == null)
                {
                    if (!m_buffers.TryTake(out m_currentBuffer, -1))
                    {
                        return 0;
                    }
                    m_readFromCurrent = 0;
                }
    
                int toRead = Math.Min(count, m_currentBuffer.Length - m_readFromCurrent);
    
                Array.Copy(m_currentBuffer, m_readFromCurrent, buffer, offset, toRead);
    
                m_readFromCurrent += toRead;
    
                if (m_readFromCurrent == m_currentBuffer.Length)
                    m_currentBuffer = null;
    
                return toRead;
            }
    
            public override void Write(byte[] buffer, int offset, int count)
            {
                throw new NotSupportedException();
            }
    
            public override bool CanRead
            {
                get { return true; }
            }
    
            public override bool CanSeek
            {
                get { return false; }
            }
    
            public override bool CanWrite
            {
                get { return false; }
            }
    
            public override long Length
            {
                get { throw new NotSupportedException(); }
            }
    
            public override long Position
            {
                get { throw new NotSupportedException(); }
                set { throw new NotSupportedException(); }
            }
        }
    
        private class WriterStream : Stream
        {
            private readonly BlockingCollection<byte[]> m_buffers;
    
            public WriterStream(BlockingCollection<byte[]> buffers)
            {
                m_buffers = buffers;
            }
    
            public override void Flush()
            {}
    
            public override long Seek(long offset, SeekOrigin origin)
            {
                throw new NotSupportedException();
            }
    
            public override void SetLength(long value)
            {
                throw new NotSupportedException();
            }
    
            public override int Read(byte[] buffer, int offset, int count)
            {
                throw new NotSupportedException();
            }
    
            public override void Write(byte[] buffer, int offset, int count)
            {
                if (count == 0)
                    return;
    
                var copied = new byte[count];
                Array.Copy(buffer, offset, copied, 0, count);
    
                m_buffers.Add(copied);
            }
    
            public override bool CanRead
            {
                get { return false; }
            }
    
            public override bool CanSeek
            {
                get { return false; }
            }
    
            public override bool CanWrite
            {
                get { return true; }
            }
    
            public override long Length
            {
                get { throw new NotSupportedException(); }
            }
    
            public override long Position
            {
                get { throw new NotSupportedException(); }
                set { throw new NotSupportedException(); }
            }
    
            protected override void Dispose(bool disposing)
            {
                m_buffers.CompleteAdding();
    
                base.Dispose(disposing);
            }
        }
    
        public Stream Reader
        {
            get { return m_reader; }
        }
    
        public Stream Writer
        {
            get { return m_writer; }
        }
    }
    

    不幸的是,您不能从同一个线程同时读取和写入这些流。但是你可以使用Task从另一个线程写:

    XDocument doc = …;
    
    var forwardingStream = new ForwardingStream();
    
    var client = new HttpClient();
    var content = new StreamContent(forwardingStream.Reader);
    
    Task.Run(() => doc.Save(forwardingStream.Writer));
    
    var response = client.Post(url, content);
    

    【讨论】:

    • 看起来很多,但大部分只是样板代码。
    猜你喜欢
    • 2016-05-07
    • 2011-10-14
    • 2015-08-20
    • 1970-01-01
    • 2019-11-04
    • 2015-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多