如何使用异步发布并使用 HttpClient 等待

Posted

技术标签:

【中文标题】如何使用异步发布并使用 HttpClient 等待【英文标题】:How to post with async and await with HttpClient 【发布时间】:2021-06-14 07:43:47 【问题描述】:

我正在编写一个 Windows 服务来从我的数据库中获取一些数据,然后将其发送给我的提供商并获得响应。我有一些问题让我模拟一个控制台应用程序来测试我的代码。

这是我的代码:

static async Task Main(string[] args)

    send();
       

public static DataSet dataAccess()

    DataSet ds = new DataSet();

    ds.Tables.Add();
    ds.Tables.Add();

    ds.Tables[0].Columns.Add("id");
    ds.Tables[0].Columns.Add("token");

    ds.Tables[1].Columns.Add("token_id");
    ds.Tables[1].Columns.Add("type");
    ds.Tables[1].Columns.Add("value");

    ds.Tables[0].Rows.Add("1", "token1");
    ds.Tables[0].Rows.Add("2", "token2");

    ds.Tables[1].Rows.Add("1", "t1", "v1");
    ds.Tables[1].Rows.Add("1", "t1", "v2");
    ds.Tables[1].Rows.Add("1", "t2", "v3");
    ds.Tables[1].Rows.Add("2", "t2", "v4");
    ds.Tables[1].Rows.Add("2", "t3", "v5");
    ds.Tables[1].Rows.Add("2", "t3", "v6");
    ds.Tables[1].Rows.Add("2", "t4", "v7");

    ds.Relations.Add("rel_token", ds.Tables[0].Columns["id"], ds.Tables[1].Columns["token_id"]);

    return ds;


private static async Task send()

    DataSet ds;
    DataTable dt;

    while (true)
    
        try
        
            ds = dataAccess();

            if (ds == null)
            
                break;
            

            List<Task> lst = new List<Task>();

            foreach (DataRow dr in ds.Tables[0].Rows)
            
                dt = dr.GetChildRows("rel_token").CopyToDataTable();
                dt.Columns.Remove("token_id");

                lst.Add(send_call((dr["token"]).ToString(), dt));
            

            await Task.WhenAll(lst);
            await Task.Delay(30000);
        
        catch (HttpRequestException e)
        
            string erMsg = e.Message;
        
    


private static HttpClient req  get; set; 

private static async Task send_call(string strToken, DataTable dt)

    try
    
        // DataTable to Json
        string strJson = "";

        foreach (DataRow dr in dt.Rows)
        
            if (dt.Rows.IndexOf(dr) > 0)
            
                strJson += ",";
            

            strJson += "";

            foreach (DataColumn dc in dt.Columns)
            
                if (dr.IsNull(dc))
                
                    continue;
                

                if (dt.Columns.IndexOf(dc) > 0)
                
                    strJson += ",";
                

                strJson += string.Format("\"0\":121",
                        dc.ColumnName,
                        dc.DataType == typeof(string) || dc.DataType == typeof(Guid) ? "\"" : null,
                        dc.DataType == typeof(bool) ? dr[dc].ToString().ToLower() : dr[dc]);
            

            strJson += "";
        
        //

        req.DefaultRequestHeaders.Add("token", strToken);

        StringContent sc = new StringContent(strJson, Encoding.UTF8, "application/json");
        HttpResponseMessage res = await req.PostAsync("my webhook url", sc);

        string response = await res.Content.ReadAsStringAsync();

        using (StreamWriter sw = new StreamWriter(@"C:\responseJson.txt", true, Encoding.UTF8))
        
            sw.WriteLine(response);
        
    
    catch (HttpRequestException e)
    
        string strError = e.Message;
    

代码说明:

我想在每次调用中分别发布每个令牌子数据, 标头值不同。 每次dataAccess()的值都不一样,我只是用了一个静态数据 用于模拟。

问题:

当我运行程序时,我在目的地没有看到任何请求,所以我开始调试并注意到指针将到达这一行:

HttpResponseMessage res = await req.PostAsync("my webhook url", sc);

但调用不会启动,然后指针返回:

await Task.WhenAll(lst);

然后是:

send();

完成了!

所以PostAsync 方法不起作用,由于response 没有填充所以responseJson.txt 没有创建。

我尝试过的事情:

我使用 await send(); 而不是 send();,但我遇到了这个错误:

System.NullReferenceException: '对象引用未设置为 对象的实例。

我已经检查了strJson。该列表已正确转换为 JSON。 我已经通过另一个程序检查了我的连接,我可以 致电my webhook url

注意:我昨天已经问过这个问题,但是因为我解释的复杂,我今天删除了它并设计了一个更小的。

【问题讨论】:

只使用send() 时没有出现异常的原因可能是因为您切断了与异步进程的所有联系。因此,如果它失败了(我的猜测是它仍然失败),调用链上没有任何东西可以捕获异常并且它会被丢弃。所以一定要使用await send(),看看为什么会出现异常。 Main() 不等待send() 完成。您需要将Main 方法更改为asyncawait send() 也值得添加catch (Exception ex) 并在其上设置刹车点。 你总是得到异常,但是当你不等待它时 - 你看不到异常。 不是创建,你需要private static HttpClient req get; set; = new HttpClient();(如果你使用新的C#版本)。或req = new HttpClient(); 在程序开始时。 【参考方案1】:

在尝试使用之前创建HttpClient,方法是使用new 关键字。

private static HttpClient req  get; set;  = new HttpClient();

public async Task Main()

    await send();

【讨论】:

以上是关于如何使用异步发布并使用 HttpClient 等待的主要内容,如果未能解决你的问题,请参考以下文章

异步等待 HttpClient.PostAsync 调用

如何等待PostAsync返回?

异步/等待和多处理

HttpWebRequest 到 HttpClient 发布请求

任务(异步,等待):我需要输入这些都是连接层还是仅具有 ASYNC 调用的层,即 HttpClient.GetAsync?

HttpClient5.0,如何在异步模式下使用gzip?