Question

Ma demande souvent des données à partir chercher une page Web en utilisant WebRequest, mais il est impossible de cliquer sur les boutons etc pendant qu'il est aller chercher. Je l'ai compris que je dois utiliser un fils / BackgroundWorker, mais je ne peux pas le faire fonctionner correctement; il ne fait pas l'interface graphique plus respondable.

Le code que je veux appliquer une sorte de filetage sur, de sorte qu'il arrête de faire ma demande unresponding:

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

Edit: Merci, lc, j'avais essayé quelque chose d'assez semblable. Mais mon problème avec l'utilisation du BackgroundWorker comme ça est; comment puis-je le QueryResult retour à la fonction qui a appelé (dans mon cas SQLGet, et dans votre cas) StartQuery?

Dans mon exemple, la chaîne retournée va être utilisé comme une variable locale dans le vide la chaîne est appelée à l'intérieur.

Et il peut y avoir de nombreuses requêtes en même temps, donc je ne veux pas risquer de l'assigner à une variable globale.

Était-ce utile?

La solution

Voici un exemple simple de la façon d'utiliser le BackgroundWorker car il applique à votre code:

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

Vous pouvez également permettre l'annulation, fournir des détails d'erreur, ou fournir une rétroaction solide qu'elle va chercher des données. Jetez un oeil à l'exemple sur la page MSDN pour plus de détails.

Le résultat de votre requête apparaîtra dans l'événement BackgroundWorker.RunWorkerCompleted comme e.Result (je l'ai stocké comme une variable d'instance dans ce cas). Si vous allez exécuter plusieurs d'entre eux en même temps, vous aurez besoin d'un moyen de différencier ce qui est la requête qui. Donc, vous devriez passer plus qu'une chaîne à la méthode. Prenez cet exemple:

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
}

Autres conseils

BackgroundWorker est une bonne solution, avec une prise en charge intégrée aux fins d'annulation et de progrès. Vous pouvez aussi utiliser HttpWebRequest.BeginGetResponse, plutôt que GetResponse, de lancer une opération de requête Web asynchrone. Cela finit par être assez simple et vous pouvez mettre en place un rappel de progression.

Pour un exemple précis de ce que vous essayez de faire, voir:

En utilisant HttpWebRequest pour les téléchargements Asynchronous

Voici une solution rapide, devrait être facile de prendre ce que vous avez besoin de lui.

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;
            }
        }
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top