2012-02-11 8 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() ожидает Stream, что может быть написано на. StreamContent ожидает поток, который можно прочитать. Таким образом, вы можете использовать два Stream s, где один действует как форвардер для другого. Я не думаю, что такой типа в рамках существует, но вы можете написать его самостоятельно:

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

Whew! Это много дополнительного кода. –

+0

Это похоже на много, но большая часть из них - только шаблонный код. – svick

+1

@downvoter, прокомментировать? – svick

 Смежные вопросы

  • Нет связанных вопросов^_^