2012-02-11 3 views
3

, 나는 XDocument.Save는() 요청 스트림에 직접를 작성하는 호출 할 수 있습니다HttpClient를 사용하여 어떻게 XDocument를 요청 스트림에 직접 저장할 수 있습니까? HttpWebRequest를 사용

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

이다 그러나 이것은 MemoryStreamXDocument다른 복사본을 만듭니다.

답변

1

XDocument.Save()에는 쓸 수있는 Stream이 필요합니다. StreamContent은 읽을 수있는 스트림을 기대합니다. 따라서 하나는 다른 하나의 전달자 역할을하는 두 개의 숫자를 사용할 수 있습니다. 나는 그런 종류의 프레임 워크에 존재 생각하지 않는다,하지만 당신은 하나를 직접 작성할 수 있습니다

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