Search code examples
c#.netasync-awaitdotnet-httpclient

How to post with async and await with HttpClient


I am writing a windows service to get some data from my database, then send it to my provider and get the response. I have some issues which make me simulate a console application to test my code.

Here is my code:

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}\":{1}{2}{1}",
                        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;
    }
}

Code explanation:

  • I want to post each token child data separately which in each call, header value is different.
  • Each time dataAccess() value is different, I just use a static data for simulation.

Issues:

When I run the program I see no request in destination, so I start debugging and noticed the pointer will reach this line:

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

But the call wouldn't initiated and after that the pointer comes back at:

await Task.WhenAll(lst);

then comes to:

send();

And finished!

So the PostAsync method didn't work and due to that response didn't fill so the responseJson.txt didn't created.

Things I have tried:

  • Instead of send(); I used await send(); but I faced this error:

System.NullReferenceException: 'Object reference not set to an instance of an object.

  • I have checked the strJson. The list converted to JSON properly.
  • I have checked my connection through another program, I could make call to my webhook url.

Note: I had asked this question yesterday but because I explained it complicatedly I deleted that today and design a smaller one.


Solution

  • Create the HttpClient before trying to use it, by using the new keyword.

    private static HttpClient req { get; set; } = new HttpClient();
    
    public async Task Main()
    {
        await send();
    }