2012-11-29 4 views
4

무언가 완료하는 데 어려움을 겪고 있습니다.파일을 비동기 적으로 클라이언트에 다운로드하십시오.

나는 asp.net MVC 4

내가 클라이언트 브라우저에 메시지 (NOT 첨부)에 관련된 이미지를 다운로드해야하는 시점에서 오전을 사용하여은 MailClient 건물입니다. -> 컨트롤러/백엔드 -

클라이언트 브라우저> 메일 서버

가 명확히하기 :

지금 내가이 설정을 가지고 내가 이미지의 콘텐츠 ID를 포함하는 클라이언트 요청이 오른쪽 사서함, 메시지 그 정보로 나는 메일 서버에서 이미지를 다운로드하여 클라이언트에 업로드 할 수 있습니다. 이제 어려운 부분이 있습니다.이 작업을 비동기로 수행하려고합니다. 나는 메일 서버에서 512KB의 덩어리를 다운로드하고, 그 부분을 디코드하고, 클라이언트에게 보내고 싶다. fetch - decode - send .. 브라우저가 이미지의 모든 데이터를 얻은 지 오래다.

저는 먼저 모든 데이터를 먼저 서버로 다운로드 한 다음 모든 데이터가 포함 된 새로운 memorystream을 만들고이를 파일 결과로 반환하고 싶지 않습니다. 나는 너무 큰 파일을 내 기억에 넣고 다른 프로세스를 차단하는 것을 너무 두려워합니다.

이 방법을 사용하여 실제 첨부 파일 (MB 수 100 개)을 업로드 할 계획입니다. 그래서 나중에 그 방법이 필요할 것입니다.

이제 메일 서버에 연결되어 있고 클라이언트에 연결되어 있기 때문에이를 어떻게 구현할지 전혀 모릅니다. 그리고 나는이 일을 위해 새로운 스트림이나 뭔가에 데이터를 전달해야합니다.

누군가 나를 도울 수 있습니까?

편집 : 명확히하기 위해 : 아니오 나는 메일 서버의 파일을 참조 할 수 없습니다. 소켓을 통해 서버에 파일을 다운로드해야합니다.

Edit2 : http chuncked가 해결책이 될 수 있습니까? 그렇다면 작은 예를 들어 주시겠습니까?

+0

어떤 종류의 클라이언트 브라우저를 지원해야합니까? 그들은 웹 소켓을 지원합니까? 본질적으로 단지 메일 서버가 스트림을 프록시로 전달하기를 원할 것입니다. 가능한 한 브라우저 지원 요구 사항이 무엇인지에 달려 있습니다. – Gijs

+0

웹 소켓을 지원할 수 없습니다 (IE 8, IE 9와 호환되어야 함). 어떻게 든 스트림을 전달하고 컨트롤러/응답에 X 양의 숯을 읽도록 말할 수 있습니까? 그게 모든 것을 해결할 수 있기 때문에 –

+0

당신의 서버가 리버스 프록시로 기능 할 수 있습니다. (클라이언트가 URL을 요청할 때 수동으로 청크하거나 소켓을 사용하지 않고 한 번에 데이터를 스트리밍합니다). 불행히도 나는 ASP.NET에 관해서는 그 이상으로 도울 수있을만큼 충분하지 않습니다. – Gijs

답변

4

한 스트림 (메일 서버에 대한 TCP 연결)에서 다른 스트림 (브라우저에 대한 HTTP 연결)으로 데이터를 복사하기 만하면됩니까? 크기를 조정하려면 this article에 설명 된대로 비 차단 IO를 사용해야합니다. 따라서 IHttpAsyncHandler 구현에서이 기사의 코드를 호출하고 싶을 것이다.

class MyHandler : IHttpAsyncHandler 
{ 
    public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) 
    { 
     Stream src = null; // remote data source 
     Stream dst = context.Response.OutputStream; 

     // set content type, etc 

     var res = new MyResult(); 

     AsynchCopy(src, dst,() => 
      { 
       ((ManualResetEvent)res.AsyncWaitHandle).Set(); 
       cb(res); 
       src.Close(); 
       dst.Flush(); 
      }); 

     return res; 
    } 

    public void EndProcessRequest(IAsyncResult result) 
    { 
    } 

    public bool IsReusable 
    { 
     get { return true; } 
    } 

    public void ProcessRequest(HttpContext context) 
    { 
     throw new NotImplementedException(); 
    } 

    class MyResult : IAsyncResult 
    { 
     public MyResult() 
     { 
      AsyncWaitHandle = new ManualResetEvent(false); 
     } 

     public object AsyncState 
     { 
      get { return null; } 
     } 

     public WaitHandle AsyncWaitHandle 
     { 
      get; 
      private set; 
     } 

     public bool CompletedSynchronously 
     { 
      get { return false; } 
     } 

     public bool IsCompleted 
     { 
      get { return AsyncWaitHandle.WaitOne(0); } 
     } 
    } 

    public static void AsynchCopy(Stream src, Stream dst, Action done) 
    { 
     byte[] buffer = new byte[2560]; 
     AsyncCallback readCallback = null, writeCallback = null; 

     readCallback = (readResult) => 
     { 
      int read = src.EndRead(readResult); 
      if (read > 0) 
      { 
       dst.BeginWrite(buffer, 0, read, writeCallback, null); 
      } 
      else 
      { 
       done(); 
      } 
     }; 

     writeCallback = (writeResult) => 
     { 
      dst.EndWrite(writeResult); 
      src.BeginRead(buffer, 0, buffer.Length, readCallback, null); 
     }; 

     src.BeginRead(buffer, 0, buffer.Length, readCallback, null); 
    } 
} 

위의 코드가 안된 및 오류 처리를 포함하지 않는, 그러나 당신이 시작 얻어야한다 :이 같은 것을하게 될 겁니다.

+0

아이디어와 샘플 코드를 보내 주셔서 감사합니다! 나는 그것에 도착할 수있는만큼 빨리 시험 할 예정이다! 우리 아키텍처에서는 구현하기가 어려울 것이라고 생각하지만 비동기 부분은 저를 구할 것입니다. 나는 그걸로 빨리 돌아갈거야! –

관련 문제