0

イントラネットで使用するファイルプロセッサを作成しています。別の質問で説明しました-C#を使用してASP.Netで多数のファイルを処理する場合のERR_EMPTY_RESPONSE

さて、上記の質問の答えで示唆されているように、私はスレッドを使用してファイル処理タスクを実行しようとしています。

しかし問題がある。ページ内のコンポーネント(asp:panel、divなど)にフィードバックを書き込むには、新しく作成したスレッドが必要です。これらのフィードバックは、いくつかのデータベース操作の結果です。

アプリケーションはそれらのtxtを読み取り、その各行を解釈して、データベースにデータを挿入します。データベースに挿入された各行は、「レジストリ'regname'が正常に挿入されました」、または「ファイル'filename'にレジストリ'regname'を挿入する際に問題が発生し、次のレジストリにスキップしました」などのフィードバックを返す必要があります。

私は非常に単純なものでテストしました:

protected void DoImport()
{
    try
    {
        MainBody.Style.Add(HtmlTextWriterStyle.Cursor, "wait");

        int x = 0;
        while (x < 10000)
        {
            ReturnMessage(String.Format("Number {0}<hr />", x), ref pnlConfirms);
            x++;
        }
    }
    catch (Exception ex)
    {
        ReturnMessage(String.Format("<font style='color:red;'><b>FATAL ERROR DURING DATA IMPORT</b></font><br /><br /><font style='color:black;'><b>Message:</b></font><font style='color:orange;'> {0}</font><br />{1}", ex.Message, ex.StackTrace), ref pnlErrors);
    }
    finally
    {
        MainBody.Style.Add(HtmlTextWriterStyle.Cursor, "default");
    }
}

この関数はPage_Loadから呼び出され、「pnlConfirms」と呼ばれるasp:panelに数値の行を入力しますが、ロード時に一度に入力します。

私はそれを次のように変更しました:

protected void DoImport()
{
    try
    {
        MainBody.Style.Add(HtmlTextWriterStyle.Cursor, "wait");
        ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
    }
    catch (Exception ex)
    {
        ReturnMessage(String.Format("<font style='color:red;'><b>FATAL ERROR DURING DATA IMPORT</b></font><br /><br /><font style='color:black;'><b>Message:</b></font><font style='color:orange;'> {0}</font><br />{1}", ex.Message, ex.StackTrace), ref pnlErrors);
    }
    finally
    {
        MainBody.Style.Add(HtmlTextWriterStyle.Cursor, "default");
    }
}

private void DoWork(Object stateInfo)
{
    int x = 0;
    while (x < 10000)
    {
        ReturnMessage(String.Format("Number {0}<hr />", x), ref pnlConfirms);
        x++;
    }
}

そして、両方ともこの関数を使用します:

public void ReturnMessage(string message, ref Panel panel, bool reset = false)
{
    if (reset)
    {
        panel.Controls.Clear();
    }
    Label msg = new Label();
    msg.Attributes.Add("width", "100%");
    msg.Text = message;
    panel.Controls.Add(msg);
}

ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));これらのasp:panelsに、挿入エラーや警告などのフィードバックを入力する必要があります。

私のコードにはすでにtry...catchステートメントの下にこれらのフィードバックがありますが、スレッドプールからasp:panelに出力されていません(DoImport()私が投稿した最初の例のように、関数から直接呼び出されたときに機能します)。

私は何か非常に間違ったことをしていますが、何がわからないのです(そして私はこれをほぼ2週間研究しています)。助けてください!

4

2 に答える 2

1

ASP.NETでは、ブラウザーがページを要求すると、そのページがレンダリングされ、処理が完了するとすぐにブラウザーに送信されるため、ブラウザーは最終的にレンダリングされたときにページを表示します。

ページをレンダリングしようとしているコードに応じて、待機カーソルを表示し、ブラウザに表示されることを期待します。その後、カーソルはデフォルトのカーソルに変更されます。説明したように、追加のスレッドを使用するかどうかに関係なく、ページは完全にレンダリングされるまでブラウザに送信されません。したがって、クライアント側に待機カーソルが表示されることはありません。

実行しようとしていることを取得するための最も簡単な待機は、Webサービス(従来の.asmxまたはWCF)とAJAX(jquery os ASP.NET AJAX)を使用することです。

1)処理を行うWebサービスを作成します

2)ブラウザーに送信されるページを作成し、javascript(jQueryまたはASP.NET AJAX)を使用してWebサービスを呼び出し、要求が処理されていることをユーザーに知らせるために何かを表示します。(待機カーソル、またはさらに良いアニメーションGIF)

3)プロセスが終了すると、JavaScriptはWebサービスから応答を取得します。ページを更新して、プロセスが終了したことをユーザーに通知できます。

javascriptの経験がない場合は、次を使用してこのタスクのほとんどを行うことができます。

  • クライアント側のjavascriptWebサービスプロキシを作成するために使用でき(他の興味深い記事)、残りのコントロールに必要なScriptManager

  • クライアント側で「プロセス実行中/プロセス終了ヒント」を更新するために使用できるいくつかのjavascript(またはjquery)。つまり、Webサービスの呼び出しが終了したら、JavaScriptを使用してDOMを使用してページを更新したり、新しいページまたは同じページに特別なパラメーターをロードしてプロセスの結果を表示したりできます。

このようにして、あなたはあなたが望むことをすることができます:

1)プロセスが実行中であることを示す状態でページを表示する

2)プロセスの終了を示す状態で、同じページまたは他のページを表示します

秘訣はブラウザとサーバーを通信することであり、これは利用可能なajaxテクニックのいくつかを使用してのみ行うことができます。

もう1つの典型的な手法は、encosia.comで説明されているように、jQuery.ajaxを使用することです。

OPメッセージによると、すべてのファイルの処理が非常に遅いため、Webサービスの呼び出しが停止します。この場合、次のソリューションを使用できます。

1)保留中のファイルの1つ(またはバッチ)を処理し、現在のファイル(またはバッチ)の処理が終了したときに少なくとも保留中のファイルの数を返すWebサービスを作成します。

2)クライアント側(javascript)から、Webサービスを呼び出します。終了したら、保留中のファイルの数を示すページを更新し、この数がゼロより大きい場合は、Webサービスを再度呼び出します。

3)Webサービスの呼び出しで保留中のファイルが0個返された場合、ページを更新して作業が終了したことを示し、それ以上呼び出さないようにすることができます。

すべてのファイルを一度に処理する場合、クライアント側でのフィードバックはなく、タイムアウトも発生します。さらに、IISは、作業を行っている作業スレッドを停止することを決定できます。IISは、いくつかの理由でこれを行います。

より信頼性の高いソリューションですが、実装が困難です。

1)ファイル処理を行うWindowsサービスを実装する

2)保留中のファイルの数を返すWebサービスを実装します(ファイルシステム、データベーステーブルなどを使用して、WindowsサービスとWebアプリを間接的に通信できます)

3)保留中のファイルの数が0になるまで、Webページからタイマー(ajaxタイマーまたはjavascript setInterval)を使用して、Webサービスを使用してN秒ごとにサーバーをポーリングします。

これを行うさらに難しい方法は、WebアプリとWindowsサービス間の間接的な通信ではなく、WindowsサービスでWCFサービスをホストすることです。このケースは、スレッドを使用して作業を行い、wcfサービスの呼び出しに参加する必要があるため、はるかに複雑です。間接的な通信を使用できる場合は、実装がはるかに簡単です。dtabseテーブルは、シンプルで効果的なソリューションです。作業プロセスは、ファイルを処理するたびにテーブルの行を更新し、Webサービスはこのテーブルから進行状況を読み取ります。

それほど単純ではない問題には、さまざまな解決策があります。

于 2012-07-05T22:38:35.343 に答える
0

新しいスレッドを開始し(またはスレッドプール内の空きスレッドの1つでコードをより正確に実行し)、メインスレッドでの結果を待機していません。このルートを使用する場合は、イベントを使用する必要があるため、Thread.Join(手動スレッド作成を使用する場合)やその他の同期メカニズムなどがあります。

リンクした質問は、実行していない非同期ページの使用を示唆しています。リクエストの処理を開始し、タスクを開始してスレッドを解放します。タスクが終了したら、リクエストを完了します。

補足:リクエストを処理するメインスレッドですべての変換を行うことを検討してください。遅いI/Oがタスクを完了することを期待しない限り、CPU作業をあるスレッドから別のスレッドに移動しても大きな利益は得られない可能性があります。現在のソリューションのパフォーマンスを測定し、アプリケーションに設定したパフォーマンス目標を満たしていないことを確認してください。(これは、楽しみ/教育目的で行う場合には適用されません)。

于 2012-07-05T21:44:59.947 に答える