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

发布于 2024-10-25 08:50:56 字数 124 浏览 3 评论 0原文

假设我开始使用 BeginGetResponse 有 50 个请求。

如何检查每个请求的状态?
以及如何取消它(有时它们会挂起)?
当所有请求都完成或取消时,我该如何执行操作?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦明 2024-11-01 08:50:56

BeginGetResponse 的调用返回一个 IAsyncResult。保留对它的引用。您可以使用 IAsyncResult.AsyncState 检查请求的状态。

要取消请求,请调用原始 WebRequest 实例的 WebRequest.Abort

要在所有请求完成或取消时执行某些操作,请从每个请求的 IAsyncResult.AsyncWaitHandle 获取 WaitHandle,然后等待所有请求。示例代码此处

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.

倒带 2024-11-01 08:50:56

您最好实施基于事件的异步模式,以便您的开发能够捕获各个不同阶段的事件。

基本上,我将如何首先创建 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 并相应地填充 Argument。

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

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

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...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文