4

私は何かを成し遂げるのに苦労しています。

asp.netMVC4を使用してメールクライアントを構築しています。

メッセージに関連する画像(添付ファイルではない)をクライアントブラウザにダウンロードする必要があります。

今、私はこの設定をしています:

クライアントブラウザ->コントローラ/バックエンド->メールサーバー

明確にするために:画像のコンテンツID、適切なメールボックス、メッセージなどを含むクライアントリクエストがあります。その情報を使用して、メールサーバーから画像をダウンロードしてクライアントにアップロードできます。ここで難しい部分があります。これを非同期で実行したいと思います。メールサーバーから512KBのチャンクをダウンロードし、その部分をデコードして、クライアントに送信できるようにしたい。フェッチ-デコード-送信..ブラウザが画像のすべてのデータを取得する限り。

最初にすべてのデータをサーバーにダウンロードしてから、そのすべてのデータを使用して新しいメモリストリームを作成し、それをfileresultとして返したくありません。メモリ内のファイルが大きすぎて、他のプロセスなどをブロックすることを恐れています。

実際の添付ファイル(数百MBになる可能性があります)をアップロードする場合にも、この方法を使用することを計画しています。だから私は後でその方法が必要になるでしょう。

メールサーバーに接続していて、クライアントにも接続しているので、これを実現する方法がわかりません。これを行うには、データを新しいストリームなどに渡す必要があります。

誰か助けてくれませんか?

編集:明確にするために:いいえ、メールサーバー上のファイルを参照できません。ソケットを介してファイルをサーバーにダウンロードする必要があります。

Edit2:httpチャンクが解決策になるでしょうか?はいの場合、簡単な例を教えていただけますか?

4

1 に答える 1

4

あるストリーム(メールサーバーへのtcp接続)から別のストリーム(ブラウザへのhttp接続)にデータをコピーする必要がありますよね?スケーリングする場合は、この記事で説明されているように、ノンブロッキング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);
    }
}

上記のコードはテストされておらず、エラー処理は含まれていませんが、開始する必要があります。

于 2012-11-30T17:04:14.260 に答える