简体   繁体   中英

C# How to “check on”, “cancel”, and wait on Async WebRequests?

Let's say I have 50 requests that I started using BeginGetResponse .

How do I check the status of each request?
and how do I cancel it (sometimes they hang)?
and how can I perform an action when ALL requests are either completed or canceled?

The call to BeginGetResponse returns an IAsyncResult . Keep a reference to it. You can use the IAsyncResult.AsyncState to check the status of the request.

To cancel the request, call WebRequest.Abort of the original WebRequest instance.

To perform something when all requests are completed or cancelled, get a WaitHandle from IAsyncResult.AsyncWaitHandle for each of your requests, then wait on them all. Sample code here .

You will be better off implementing Event Based Asynchronous Pattern for your development to catch events at all different stages.

Basically, how I would go by first creating an IAsyncCommand interface as follows.

    public interface IAsyncCommand<TRequest, TResponse, TCorrelation> : ICommand<TRequest, TResponse>
{
    event CommandProgressChangedEventHandler<string, TCorrelation> ProgressChanged;
    event CommandCompletedEventHandler<TResponse, TCorrelation> Completed;

    bool CancellationPending { get; }
    bool IsBusy { get; }

    TCorrelation CorrelationId(TRequest request);
    void ExecuteAsync(TRequest request);
    void ExecuteAsync(TRequest request, CommandCompletedEventHandler<TResponse, TCorrelation> completedCallback, CommandProgressChangedEventHandler<string, TCorrelation> progressCallback);
    void CancelAsync();
}

implement those two CommandProgressChangedEventHander and the CommandCompletedEventHandler based on your scenario and populate the Argument accordingly.

If we are assuming that our thread should check whether particular URL in question is an valid URL, the code goes as follows....

    public class UrlCheckCommand : AsyncCommandBase<string, bool, string>, IUrlCheckCommand
{
    public override string CorrelationId(string request)
    {
        return request;   //Guid.NewGuid().ToString();
    }

    public override bool Execute(string request)
    {
        return CommandHelper.CheckUrlValidity(request);
    }
}

The AsyncCommandBase class is an abstract class which implements IAsyncCommand interface. The skeleton for this class is defined below.

    public abstract class AsyncCommandBase<TRequest, TResponse, TCorrelation> : IAsyncCommand<TRequest, TResponse, TCorrelation>
{
    protected AsyncOperation operation = null;
    protected BackgroundWorker worker = null;

    #region IAsyncCommand<TRequest,TResponse,TCorrelation> Members

        //Implement all the interface members as per your use....

    #endregion

    protected void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        e.Result = Execute((TRequest)e.Argument);
    }
    protected void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        OnProgressChanged(e);
    }
    protected void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        OnCompleted(e);
    }

    protected void ReportProgress(int percentageProgress, string message)
    {
        if (worker != null && worker.WorkerReportsProgress)
            worker.ReportProgress(percentageProgress, message);
        else
            OnProgressChanged(new ProgressChangedEventArgs(percentageProgress, message));
    }
    protected void OnProgressChanged(ProgressChangedEventArgs e)
    {
        if (ProgressChanged != null)
        {
            SendOrPostCallback callback = new SendOrPostCallback(delegate { ProgressChanged(this, new CommandProgressChangedEventArgs<string, TCorrelation>(e.ProgressPercentage, e.UserState as string, (TCorrelation)operation.UserSuppliedState)); });
            operation.Post(callback, null);
        }
    }
    protected void OnCompleted(RunWorkerCompletedEventArgs e)
    {
        if (Completed != null)
        {
            TResponse response = default(TResponse);
            if (e.Error == null)
                response = (TResponse)e.Result;

            SendOrPostCallback callback = new SendOrPostCallback(delegate { Completed(this, new CommandCompletedEventArgs<TResponse, TCorrelation>(response, e.Error, (TCorrelation)operation.UserSuppliedState, e.Cancelled)); });
            operation.PostOperationCompleted(callback, null);
        }
    }
}

You can populate the Progress and Completed Event handler and they key to is the Argument population. You can even use it for filling the progresspercentage, userstate etc...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM