将Async/AwaitJSON反序列化结果移动到另一个函数

c#

我有这个功能,最多可以获取 10 个项目作为输入列表

public async Task<KeyValuePair<string, bool>[]> PayCallSendSMS(List<SmsRequest> ListSms)
{
    List<Task<KeyValuePair<string, bool>>> tasks = new List<Task<KeyValuePair<string, bool>>>();

    foreach (SmsRequest sms in ListSms)
    {
        tasks.Add(Task.Run(() => SendSMS(sms)));
    }

    var result = await Task.WhenAll(tasks);
    return result;
}

在这个函数中,我await要下载一些 JSON,然后反序列化它。

public async Task<KeyValuePair<string, bool>> SendSMS(SmsRequest sms)
 {
    //some code
      using (WebResponse response = webRequest.GetResponse())
    {
        using (Stream responseStream = response.GetResponseStream())
        {
            StreamReader rdr = new StreamReader(responseStream, Encoding.UTF8);
            string Json = await rdr.ReadToEndAsync();
            deserializedJsonDictionary = (Dictionary<string, object>)jsonSerializer.DeserializeObject(Json);
        }
    }
    //some code
     return  GetResult(sms.recipient);
 }

public KeyValuePair<string, bool> GetResult(string recipient)
{
    if (deserializedJsonDictionary[STATUS].ToString().ToLower().Equals("true"))
    {
        return new KeyValuePair<string, bool>(recipient, true);
    }
    else // deserializedJsonDictionary[STATUS] == "False"
    {
        return new KeyValuePair<string, bool>(recipient, false);
    }
}

我的问题在于return GetResult();其中deserializedJsonDictionary为空的部分(并且因为 json 还没有完成下载)。

但我不知道如何解决

我尝试使用ContinueWith但它对我不起作用。

我愿意接受对我的原始代码和/或解决方案设计的任何更改

回答

  • 不相关的提示:不要滥用KeyValuePair<>,而是使用 C# 7 值元组(尤其是因为它们更容易阅读)。
  • 使用foreach循环来构建 aList<Task>很好 - 尽管使用它可以更简洁.Select()。我在回答中使用了这种方法。
  • 但不要Task.Run古老的 WebRequest( HttpWebRequest) 类型一起使用。而是使用HttpClient它完全支持异步 IO。
  • 此外,您应该遵守 .NET 命名约定:
    • 所有异步方法都应该有Async一个方法名后缀(例如PayCallSendSMS应该命名PayCallSendSmsAsync)。
    • 长度超过 2 个字符的首字母缩略词和首字母缩写词应使用 PascalCase,而不是CAPS,因此请使用Sms代替SMS
    • 使用camelCase, 不适PascalCase用于参数和局部变量 - 并且List是一个冗余前缀。更好的名称ListSmssmsRequests因为它的类型是List<SmsRequest>)。
  • 一般来说,参数应该使用所需的最少特定类型来声明 -特别是集合参数,考虑将它们键入为IEnumerable<T>IReadOnlyCollection<T>代替T[]List<T>等)。
  • 您需要首先检查来自远程服务器的响应实际上是 JSON 响应(而不是 HTML 错误消息或 XML 响应)并且具有预期的状态代码 - 否则您将尝试反序列化不是 JSON 的内容。
  • 也考虑支持CancellationToken(这不包括在我的答案中,因为它增加了太多的视觉噪音)。
  • 始终使用Dictionary.TryGetValue而不是盲目地假设字典索引器会匹配。

public async Task< IReadOnlyList<(String recipient, Boolean ok)> > PayCallSendSmsAsync( IEnumerable<SmsRequest> smsRequests )
{
    using( HttpClient httpClient = this.httpClientFactory.Create() )
    {
        var tasks = smsRequests
            .Select(r => SendSmsAsync(httpClient, r))
            .ToList(); // <-- The call to ToList is important as it materializes the list and triggers all of the Tasks.

        (String recipient, Boolean ok)[] results = await Task.WhenAll(tasks);
        return results;
    }
}

private static async Task<(String recipient, Boolean ok)> SendSmsAsync(HttpClient httpClient, SmsRequest smsRequest)
{
    using (HttpRequestMessage request = new HttpRequestMessage( ... ) )
    using (HttpResponseMessage response = await httpClient.SendAsync(request).ConfigureAwait(false))
    {
        String responseType = response.Content.Headers.ContentType?.MediaType ?? "";
        if (responseType != "application/json" || response.StatusCode != HttpStatusCode.OK)
        {
            throw new InvalidOperationException("Expected HTTP 200 JSON response but encountered an HTTP " + response.StatusCode + " " + responseType + " response instead." );
        }

        String jsonText = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
        
        Dictionary<String,Object> dict = JsonConvert.DeserializeObject< Dictionary<String,Object> >(jsonText);

        if(
            dict != null &&
            dict.TryGetValue(STATUS, out Object statusValue) &&
            statusValue is String statusStr &&
            "true".Equals( statusStr, StringComparison.OrdinalIgnoreCase )
        )
        {
            return ( smsRequest.Recipient, ok: true );
        }
        else
        {
            return ( smsRequest.Recipient, ok: false );
        }
    }
}


以上是将Async/AwaitJSON反序列化结果移动到另一个函数的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>