C#如何“检查”、“取消”和等待异步Web请求?

5

假设我使用BeginGetResponse发起了50个请求。

如何检查每个请求的状态?
如果有请求挂起,如何取消它?
当所有请求都完成或取消时,如何执行操作?


有没有完整的源代码的最终解决方案? - Kiquenet
2个回答

7
调用 BeginGetResponse 返回一个 IAsyncResult。保留对它的引用。您可以使用 IAsyncResult.AsyncState 检查请求的状态。
要取消请求,请调用原始 WebRequest 实例的 WebRequest.Abort
要在所有请求完成或取消时执行某些操作,请从每个请求的 IAsyncResult.AsyncWaitHandle 获取 WaitHandle,然后等待它们全部完成。示例代码在此处

0

在编程开发中,你最好采用基于事件的异步模式来捕获各个阶段的事件。

基本上,我会首先创建一个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();
}

根据您的方案实现这两个CommandProgressChangedEventHandler和CommandCompletedEventHandler,并相应地填充参数。

如果我们假设我们的线程应该检查所讨论的特定URL是否是有效的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);
        }
    }
}

您可以填充进度和完成事件处理程序,关键是参数的填充。您甚至可以使用它来填充进度百分比、用户状态等...


他不是从头开始构建异步API,而是使用现有的API,你没有提到。http://msdn.microsoft.com/zh-cn/library/system.net.httpwebrequest.begingetresponse.aspx - Robert Levy
@Robert - 我自己也问过同样的问题(更突出的是如何捕获未完成或取消的事件),并使用基于事件的异步模式以更好的方式解决了它。如果您可以使用线程API来创建自己的API,那么这确实可以解决所有问题。我已经从我的当前应用程序中复制了这些代码行。URLCheck只是GetWebRequest的替代品。请仔细阅读代码。 - DotNetInfo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接