1

私のアプリケーションは WebRequest を使用して Web ページからデータをフェッチすることがよくありますが、フェッチ中にボタンなどをクリックすることはできません。スレッド/バックグラウンドワーカーを使用する必要があることは理解しましたが、正しく機能させることができません。GUI の応答性が向上するわけではありません。

アプリケーションが応答しなくなるのを防ぐために、ある種のスレッド化を適用したいコード:

public string SQLGet(string query)
{
    string post = "q=" + query;
    WebRequest request = WebRequest.Create("http://test.com");
    request.Timeout = 20000;
    request.Method = "POST";
    byte[] bytes = Encoding.UTF8.GetBytes(post);
    request.ContentType = "application/x-www-form-urlencoded";
    request.ContentLength = bytes.Length;

    Stream requestStream = request.GetRequestStream();
    requestStream.Write(bytes, 0, bytes.Length);
    requestStream.Close();

    WebResponse response = request.GetResponse();
    requestStream = response.GetResponseStream();
    StreamReader reader = new StreamReader(requestStream);
    string ret = reader.ReadToEnd();

    reader.Close();
    requestStream.Close();
    response.Close();

    return ret;
}

編集:ありがとう、lc、私はそれにかなり似たものを試しました。しかし、そのようにバックグラウンドワーカーを使用することに関する私の問題は次のとおりです。(私の場合は SQLGet、あなたの場合は) StartQuery を呼び出した関数に queryResult を戻すにはどうすればよいですか?

私の例では、返された文字列は、文字列が内部で呼び出される void のローカル変数として使用されます。

また、同時に多くのクエリが存在する可能性があるため、グローバル変数に割り当てるリスクを冒したくありません。

4

3 に答える 3

5

BackgroundWorkerをコードに適用する方法の簡単な例を次に示します。

private void StartQuery(string query)
{
    BackgroundWorker backgroundWorker1 = new BackgroundWorker();
    backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
    backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
    backgroundWorker1.RunWorkerAsync(query);
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{   
    e.Result = SQLGet((string)e.Argument);
}

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    queryResult = (string)e.Result;
}

また、キャンセルを許可したり、エラーの詳細を提供したり、データをフェッチする際に確実なフィードバックを提供したりすることもできます。詳細については、MSDN ページの例を参照してください。

クエリの結果は、BackgroundWorker.RunWorkerCompletedイベントに次のように表示されe.Resultます (この場合、インスタンス変数として保存しました)。これらの多くを同時に実行する場合は、どのクエリがどれであるかを区別する方法が必要になります。したがって、メソッドには単なる文字列以上のものを渡す必要があります。次の例を見てください。

private int NextID = 0;

private struct QueryArguments
{
    public QueryArguments()
    {
    }

    public QueryArguments(int QueryID, string Query)
        : this()
    {
        this.QueryID = QueryID;
        this.Query = Query;
    }

    public int QueryID { get; set; }
    public string Query { get; set; }
    public string Result { get; set; }
}

private int StartQuery(string query)
{
    QueryArguments args = new QueryArguments(NextID++, query);

    BackgroundWorker backgroundWorker1 = new BackgroundWorker();
    backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
    backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
    backgroundWorker1.RunWorkerAsync(args);

    return args.QueryID;
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{   
    QueryArguments args = (QueryArguments)e.Argument;
    args.Result = SQLGet(args.Query);
    e.Result = args;
}

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    QueryArguments args = (QueryArguments)e.Result;
    //args.Result contains the result

    //do something
}
于 2009-07-09T03:54:26.793 に答える
3

BackgroundWorkerは優れたソリューションであり、キャンセルと進行のサポートが組み込まれています。GetResponseではなくHttpWebRequest.BeginGetResponseを使用して、非同期Web要求操作を開始することもできます。これは非常に単純になり、進行状況のコールバックを設定できます。

あなたがやろうとしていることの正確な例については、以下を参照してください。

非同期ダウンロードにHttpWebRequestを使用する

于 2009-07-09T12:33:11.107 に答える
2

ここに簡単な解決策があります。必要なものを簡単に取得できるはずです。

using System;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Text;

namespace ConsoleApplication5
{
    class Program
    {
        static void Main(string[] args)
        {
            BackgroundWorker b = new BackgroundWorker();
            b.DoWork += new DoWorkEventHandler(b_DoWork);
            b.RunWorkerCompleted += new RunWorkerCompletedEventHandler(b_RunWorkerCompleted);
            b.RunWorkerAsync("My Query");

            while(b.IsBusy)
            {

            }
            Console.ReadLine();
        }

        static void b_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if(e.Result is string)
            {
                Console.WriteLine((string)e.Result);
            }
        }

        static void b_DoWork(object sender, DoWorkEventArgs e)
        {
            if (e.Argument is string)
            {
                string post = "q=" + (string) e.Argument;
                WebRequest request = WebRequest.Create("http://test.com");
                request.Timeout = 20000;
                request.Method = "POST";
                byte[] bytes = Encoding.UTF8.GetBytes(post);
                request.ContentType = "application/x-www-form-urlencoded";
                request.ContentLength = bytes.Length;
                Stream requestStream = request.GetRequestStream();
                requestStream.Write(bytes, 0, bytes.Length);
                requestStream.Close();
                WebResponse response = request.GetResponse();
                requestStream = response.GetResponseStream();
                StreamReader reader = new StreamReader(requestStream);
                string ret = reader.ReadToEnd();
                reader.Close();
                requestStream.Close();
                response.Close();
                e.Result = ret;
            }
        }
    }
}
于 2009-07-09T03:58:56.987 に答える