首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >HttpClient异步任务管理

HttpClient异步任务管理
EN

Stack Overflow用户
提问于 2013-12-12 22:34:27
回答 3查看 1.2K关注 0票数 0

我正在创建一个通用加载程序,我想启动一个HttpClient SendAsync请求。但是,其中一些请求可能需要时间,因此我希望添加取消选项,并在完成后通知。

这似乎是一个标准的场景-- imho。

我不确定这是否是正确的方法,但根据我看过的一些例子,这是我的立场。如果您查看代码的底部,我的问题是--在这一点上,是否检查响应并引发成功或错误事件

代码语言:javascript
复制
    public bool StartFetch()
    {
        if (IsFetching) return false;
        IsFetching = true;

        mCancellationTokenSource = new CancellationTokenSource();

        // this is not awaited, so execution should continue
        StartTask(request, mCancellationTokenSource.Token);
        return true;
    }

    public bool CancelFetch()
    {
        // send cancellation
        if (mCancellationTokenSource != null)
            mCancellationTokenSource.Cancel();

        Cleanup();
        return true;
    }


    private async Task StartTask(LFHttpRequest request, CancellationToken cancellationToken)
    {
        var message = new HttpRequestMessage(request.Method, request.Uri);
        var response = await HttpClient.SendAsync(message, cancellationToken); 

        // at this point, do I take a look at response and raise a custom OnSuccess or OnError event???   

       // or do I want to grab the task from `SendAsync`, check for completed or faulted?
    }
EN

回答 3

Stack Overflow用户

发布于 2013-12-13 00:14:44

当您查看与任务相关的状态(如IsFetching )时,只公开Task本身通常更干净、更容易。

就像这样:

代码语言:javascript
复制
public Task<T> FetchTask { get; private set; }

public bool StartFetch()
{
    if (FetchTask != null) return false;

    mCancellationTokenSource = new CancellationTokenSource();
    FetchTask = FetchAsync(request, mCancellationTokenSource.Token);
    return true;
}

public bool CancelFetch()
{
    // send cancellation
    if (mCancellationTokenSource != null)
        mCancellationTokenSource.Cancel();

    FetchTask = null;
    return true;
}


private async Task<T> FetchAsync(LFHttpRequest request, CancellationToken cancellationToken)
{
    var message = new HttpRequestMessage(request.Method, request.Uri);
    var response = await HttpClient.SendAsync(message, cancellationToken); 
    response.EnsureSuccessStatusCode();
    var ret = // Convert response.Content into T.
    return ret;
}
票数 3
EN

Stack Overflow用户

发布于 2013-12-12 22:49:02

如果InvalidOperationException状态无效,建议为StartFetchCancelFetch操作抛出IsFetching s。这可能看起来很烦人,但它让您在程序员错误和线程问题成为一个更大、更隐蔽的问题之前就可以捕捉到它们。

至于异步方法,您的方法应该返回一个结果。所以也许类似于private async Task<MyHttpResult> StartTask(...)。您的结果应该包含确定成功、失败和取消的方法。

例如:

代码语言:javascript
复制
public sealed class MyHttpResult
{
  public HttpResponse Result { get; private set; }
  public Exception Error { get; private set; }
  public bool WasCancelled { get; private set; }

  public MyHttpResult(HttpResponse result, Exception error, bool wasCancelled)
  {
    this.Result = result;
    this.Error = error;
    this.WasCancelled = wasCancelled;
  }
}

如果取消了许多异步方法,它们将抛出一个TaskCanceledException,因此您可以使用catch来表示它,如下所示:

代码语言:javascript
复制
async Task<MyHttpResult> StartTask(LFHttpRequest request, CancellationToken cancellationToken)
{
  var message = new HttpRequestMessage(new HttpMethod(request.Method), request.Uri);

  HttpResponse response = null;
  Exception lastError = null;
  bool wasCancelled = false;

  try
  {
    response = await MessageInvoker.SendAsync(message, cancellationToken);
  }
  catch(TaskCanceledException)
  {
    wasCancelled = true;
  }
  catch(Exception ex)
  {
    lastError = ex;
  }

  var result = new MyHttpResult(response, lastError, wasCancelled);
  return result;
}

这都是假设您的观察者也是调用者,所以他们可以await这个方法。如果不是这样的话,您对EventHandler的想法是有意义的。您可以创建如下所示的自定义EventArgs类,而不是返回结果:

代码语言:javascript
复制
public delegate void TaskResultEventHandler<T>(object sender, TaskResultEventArgs<T> e);

public sealed class TaskResultEventArgs<T> : EventArgs
{
      public T Result { get; private set; }
      public Exception Error { get; private set; }
      public bool WasCancelled { get; private set; }

      public TaskResultEventArgs(T result, Exception error, bool wasCancelled)
      {
        this.Result = result;
        this.Error = error;
        this.WasCancelled = wasCancelled;
      }
}

然后,这只是一个公开一个TaskResultEventHandler<HttpResponse>和您的观察者订阅它的问题。您可以这样调用它:

代码语言:javascript
复制
var handler = this.HttpTaskCompleted;

if(handler != null)
  handler(this, new TaskResultEventArgs<HttpResponse>(response, lastError, wasCancelled));
票数 0
EN

Stack Overflow用户

发布于 2013-12-14 17:14:53

在你等待http电话之后

代码语言:javascript
复制
var response = await HttpClient.SendAsync(message, cancellationToken); 

您应测试是否取消:

代码语言:javascript
复制
if(cancellationToken.IsCancellationRequested)
   //... do what you want, throw or return false or null, depending on how you want to handle this cancellation.

或者您可以在一个调用中检查并抛出Microsoft异常:

代码语言:javascript
复制
cancel.ThrowIfCancellationRequested();
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20555683

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档