异步/等待处理HttpResponseMessage组

时间:2015-06-02 19:55:17

标签: c# asynchronous async-await

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链接到成员使得使用上面的代码变得不现实,或者有没有办法以某种方式将成员作为任务结果的一部分返回?

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

  

我需要将每个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];
      ...
    }
  }
}