C # Как «проверить», «отменить» и ждать на Async WebRequests? - PullRequest
5 голосов
/ 23 марта 2011

Допустим, у меня есть 50 запросов, которые я начал использовать BeginGetResponse.

Как проверить статус каждого запроса?
и как мне его отменить (иногда они зависают)?
и как я могу выполнить действие, когда ВСЕ запросы либо выполнены, либо отменены?

Ответы [ 2 ]

7 голосов
/ 23 марта 2011

Вызов BeginGetResponse возвращает IAsyncResult. Держите ссылку на это. Вы можете использовать IAsyncResult.AsyncState для проверки статуса запроса.

Чтобы отменить запрос, вызовите WebRequest.Abort исходного экземпляра WebRequest.

Чтобы выполнить что-либо, когда все запросы завершены или отменены, получите WaitHandle от IAsyncResult.AsyncWaitHandle для каждого из ваших запросов, затем дождитесь их всех. Пример кода здесь .

0 голосов
/ 23 марта 2011

Вам будет лучше реализовать Асинхронный шаблон на основе событий , чтобы ваша разработка могла отлавливать события на всех различных этапах.

По сути, как бы я сначала создал интерфейс IAsyncCommand следующим образом.

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

реализуйте эти два CommandProgressChangedEventHander и CommandCompletedEventHandler на основе вашего сценария и заполните Аргумент соответствующим образом.

Если мы предполагаем, что наша ветка должна проверить, является ли конкретный рассматриваемый URL допустимым, код выглядит следующим образом ...

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

Класс AsyncCommandBase - это абстрактный класс, который реализует интерфейс IAsyncCommand. Скелет для этого класса определен ниже.

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

Вы можете заполнить обработчик Progress и Completed Event, и они являются ключом к населению Argument. Вы даже можете использовать его для заполнения процентов прогресса, состояния пользователя и т. Д. *

...