Asynchroniczne pobieranie

0

Witam

Znalazłem w sieci przykład pobierania asynchronicznego.
Chciałbym umieścić go w osobnej klasie, a nie dołączać do głównej klasy mojego programu.

Z mojej klasy wywołuję:

Net.ScanSites("http://www.jakas.strona");

Nie wiem jak powiadomić główną klasę o zdarzeniach tj. zakończenie downloadu czy przekazanie wyniku.
Próbowałem z delegatami, ale nie udało mi się nic sensownego zrobić. Oto kod:


    
    public class Net
    {

        public static void ScanSites(string uriString)
        {
            WebRequest request = HttpWebRequest.Create(uriString);
            request.Method = "GET";

            object data = new object(); //container for our "Stuff"

            // RequestState is a custom class to pass info to the callback
            RequestState state = new RequestState(request, data, uriString);

            IAsyncResult result = request.BeginGetResponse(new AsyncCallback(WwwSrc), state);
            

            //Register the timeout callback
            ThreadPool.RegisterWaitForSingleObject(
            result.AsyncWaitHandle,
            new WaitOrTimerCallback(ScanTimeoutCallback),
            state,
            (10 * 1000), // 10 second timeout
            true
            );
        }


        private static void WwwSrc(IAsyncResult result)
        {

            try
            {
                // grab the custom state object
                RequestState state = (RequestState)result.AsyncState;
                WebRequest request = (WebRequest)state.Request;

                // get the Response
                HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);

                //jesli bylo abort dalej nie idzie
                Stream s = (Stream)response.GetResponseStream();
                StreamReader readStream = new StreamReader(s);

                // dataString will hold the entire contents of the requested page if we need it.
                string dataString = readStream.ReadToEnd(); //<< tutaj zawartosc strony
                response.Close();
                s.Close();
                readStream.Close();


            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            

        }

        private static void ScanTimeoutCallback(object state, bool timedOut)
        {
            if (timedOut)
            {
                RequestState reqState = (RequestState)state;
                if (reqState != null)
                    reqState.Request.Abort();
                //Console.WriteLine("aborted- timeout");
            }
        }

    }

    public class RequestState
    {

        public WebRequest Request; // holds the request
        public object Data; // store any data in this
        public string SiteUrl; // holds the UrlString to match up results (Database lookup, etc).

        public RequestState(WebRequest request, object data, string siteUrl)
        {
            this.Request = request;
            this.Data = data;
            this.SiteUrl = siteUrl;
        }
    }


 
0

Zamiast w metodzie ScanSites tworzyć nowy delegat:

IAsyncResult result = request.BeginGetResponse(new AsyncCallback(WwwSrc), state); 

po prostu udostępnij go na zewnątrz klasy:

public AsyncCallback WwwSrc; 

i podepnij metodę pod ten delegat:

Net.WweSrc += //tu odpowiednia metoda o sygnaturze zgadzającej się z typem AsyncCallback, zdefiniowana poza klasą Net. 

Tylko przy wywoływaniu musisz pamiętać o sprawdzaniu czy WwwSrc na pewno pokazuje na jakąś metodę

if(WwwSrc != null)
{
 //i cala reszta zwiazana z wywolaniem delegata tutaj
}
0

Dodam jeszcze, że wykonanie EndGetResponse() zaraz po BeginGetResponse() spowoduje zatrzymanie wątku do czasu, aż operacja asynchroniczna dobiegnie końca - może to rozwiąże twój problem?

0

Niestety nie dam rady z tymi delegatami.

0

Poradziłem sobie w następujący sposób. Jeśli powinienem to zrobić inaczej, proszę o komentarz.
Gwiazdkami zaznaczyłem dodane fragmenty kodu.

    public class MyEventArgs : EventArgs // (***********
    {
        private string data;
 
        public MyEventArgs(string data)
        {
            this.data = data;
        }
 
        public string Data
        {
            get { return data; }
            set { data = value; }
        }
 
    } // ***********)
 
    public delegate void EndDownload(object sender, MyEventArgs e); // ***********
 
    public class Net
    {
 
        public static event EndDownload MyWww; // ***********
 
        public static void ScanSites(string uriString)
        {
            WebRequest request = HttpWebRequest.Create(uriString);
            request.Method = "GET";
 
            object data = new object(); //container for our "Stuff"
 
            // RequestState is a custom class to pass info to the callback
            RequestState state = new RequestState(request, data, uriString);
 
            IAsyncResult result = request.BeginGetResponse(new AsyncCallback(WwwSrc), state);
 
 
            //Register the timeout callback
            ThreadPool.RegisterWaitForSingleObject(
            result.AsyncWaitHandle,
            new WaitOrTimerCallback(ScanTimeoutCallback),
            state,
            (10 * 1000), // 10 second timeout
            true
            );
        }
 
 
        private static void WwwSrc(IAsyncResult result)
        {
 
            try
            {
                // grab the custom state object
                RequestState state = (RequestState)result.AsyncState;
                WebRequest request = (WebRequest)state.Request;
 
                // get the Response
                HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
 
                //jesli bylo abort dalej nie idzie
                Stream s = (Stream)response.GetResponseStream();
                StreamReader readStream = new StreamReader(s);
 
                // dataString will hold the entire contents of the requested page if we need it.
                string dataString = readStream.ReadToEnd(); //<< tutaj zawartosc strony
                response.Close();
                s.Close();
                readStream.Close();
 
                MyEventArgs www = new MyEventArgs(dataString); // (***********
 
                if (MyWww != null)
                    MyWww("ok", www); // ***********)
 
 
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
 
 
        }
 
        private static void ScanTimeoutCallback(object state, bool timedOut)
        {
            if (timedOut)
            {
                RequestState reqState = (RequestState)state;
                if (reqState != null)
                {
                    reqState.Request.Abort();
 
                    MyEventArgs www = new MyEventArgs("");// (***********
                    if (MyWww != null)
                        MyWww("error", www);// ***********)
 
                 }
                //Console.WriteLine("aborted- timeout");
            }
        }
 
    }
 
    public class RequestState
    {
 
        public WebRequest Request; // holds the request
        public object Data; // store any data in this
        public string SiteUrl; // holds the UrlString to match up results (Database lookup, etc).
 
        public RequestState(WebRequest request, object data, string siteUrl)
        {
            this.Request = request;
            this.Data = data;
            this.SiteUrl = siteUrl;
        }
    }

W głównej klasie podpinam:

Net.MyWww += new EndDownload(Net_MyWww);
 
void Net_MyWww(object sender, MyEventArgs e)
{
    //obsługa 
}

Chciałbym jeszcze dodać możliwość zatrzymania pobierania,
ale mam z tym mały problem.

0

Męczę się już z tym i nie wiem jak to ugryźć.
Wywołuję metodę Net.ScanSites("http://www.jakas.strona") dla powiedzmy 100 adresów,
ale po pobraniu np. 20, chciałbym anulować resztę wątków. Jak je zatrzymać?

1 użytkowników online, w tym zalogowanych: 0, gości: 1