【问题标题】:Async/Await handling group of HttpResponseMessageHttpResponseMessage 的 Async/Await 处理组
【发布时间】:2015-06-02 19:55:17
【问题描述】:

previously posted 提出了一个关于将 HTTPClient 与 async/await 一起使用的问题。现在我试图弄清楚如何做到这一点,以便实际使 Post 调用同时执行,同时仍然能够处理生成的 HttpResponseMessage

这就是我想出的。但是,作为等待/异步的菜鸟,我仍然不确定我是否正确执行此操作。有人可以验证这是执行此操作的正确方法……或者至少是正确的方法。

public async Task ProcessAsync() {
   //Query lists
   List<Member> list = dbContext.Users.Where(u => u.IsMember).ToList();
   //Add members to mailing list through web service
   await AddMembersAsync(list);
 }

 private async Task AddMembersAsync(List<Member> members) {
     using(var _client = new HttpClient()) {
         //Initialize Http Client
         ...
         var responses = await Task.WhenAll(members.Select(x => PostMemberAsync(x,_client)));
         await Task.WhenAll(responses.Select(r => ProcessResponseAsync(r,client)));
     }
 }

 private async Task<HttpResponseMessage> PostMemberAsync(Member member, HttpClient client) {
    var jss = new JavaScriptSerializer();
    var content = jss.Serialize(new MemberPost() {
       email_address = member.email,
       ... 
    });
    return await client.PostAsync("uri",new StringContent(content, Encoding.UTF8, "application/json"));
 }

 private async Task ProcessResponsesAsync(HttpResponseMessage response, HttpClient client) {
    if(response.IsSuccessStatusCode) {
       var responseText = await response.Content.ReadAsStringAsync();
       var jss = new JavaScriptSerializer();
       var userid = jss.Deserialize<MemberResponse>(responseText);
       //Store mailing user's id
       ...
    }
    response.Dispose();
 }

这在我看来是正确的。但是,我对此有一个小问题。我需要将每个HttpResponseMessage 绑定到为其创建消息的成员。我当前的代码仅返回 Task 但响应消息不包含指向用户的链接。 (我发布到的服务返回一个特定于该服务的 ID。我需要跟踪每个用户的该 ID,以便在成员 ID 和服务 ID 之间建立链接)。

我将响应消息中的 id 链接到成员的要求是否使使用上述代码变得不切实际,或者有没有办法以某种方式将成员作为任务结果的一部分返回?

【问题讨论】:

  • public async ProcessAsync() 不是有效代码,没有返回类型或者它是一个不能异步的构造函数。
  • 谢谢,我忘记了我的Task 返回值。我已经修复了代码。

标签: c# asynchronous async-await


【解决方案1】:

我建议这个没有尝试,所以请小心,但我会替换这两行:

var responses = await Task.WhenAll(members.Select(x => PostMemberAsync(x,_client)));
     await Task.WhenAll(responses.Select(r => ProcessResponseAsync(r,client)));

用这个:

await Task.WhenAll(members.Select(async x => 
{ 
   var response = await PostMemberAsync(x, _client);
   await ProcessResponseAsync(response, client, x);
}));

当然你需要通过参数 Member 来增强 ProcessResponseAsync

【讨论】:

    【解决方案2】:

    我需要将每个 HttpResponseMessage 绑定到为其创建消息的成员。

    在进行异步编程时,我发现避免副作用很有用。换句话说,如果您有一个计算或确定某事的方法,请从该方法返回该值,而不是将其保存在某个成员变量中。

    private async Task<MemberResponse> ProcessResponseAsync(HttpResponseMessage response, HttpClient client)
    {
      using (response)
      {
        if(response.IsSuccessStatusCode)
        {
          var responseText = await response.Content.ReadAsStringAsync();
          var jss = new JavaScriptSerializer();
          var userid = jss.Deserialize<MemberResponse>(responseText);
          return userid;
        }
        else
        { ... }
      }
    }
    

    添加一个小的辅助方法,你的调用代码变得非常干净:

    private async Task<HttpResponseMessage> ProcessMemberAsync(Member member, HttpClient client)
    {
      var response = await PostMemberAsync(member, client);
      return await ProcessResponseAsync(response, client);
    }
    
    private async Task AddMembersAsync(List<Member> members)
    {
      using(var client = new HttpClient())
      {
        ... // Initialize HttpClient
        var responses = await Task.WhenAll(members.Select(x => ProcessMemberAsync(x, client)));
        for (int i = 0; i != members.Count; ++i)
        {
          var member = members[i];
          var response = responses[i];
          ...
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-10-15
      • 2020-09-22
      • 1970-01-01
      • 2021-04-10
      • 1970-01-01
      • 2016-08-04
      • 2023-04-10
      • 1970-01-01
      • 2021-10-24
      相关资源
      最近更新 更多