2012-02-11 28 views
3

使用HttpWebRequest的,我可以調用XDocument.Save()寫直接請求流:使用HttpClient,如何將XDocument直接保存到請求流?

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

但是這創造XDocument的另一副本在MemoryStream

回答

1

XDocument.Save()預計可以寫入的StreamStreamContent需要可以讀取的流。所以,你可以使用兩個Stream,其中一個充當另一個的轉發者。我不認爲在框架中存在這樣的類型,但你可以自己寫一個:

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); 
+0

嗚!這是很多額外的代碼。 – 2012-02-11 20:30:35

+0

看起來很多,但大部分只是樣板代碼。 – svick 2012-02-11 20:33:19

+1

@downvoter,關心評論? – svick 2012-02-11 21:08:37

相關問題