-1

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.

Amirali Sam
  • 387
  • 9
  • 21
  • 3
    The reason you're not getting an exception when just using `send()` is probably because you cut all ties with the asynchronous process. So if it fails (and my guess is that it still fails) there is nothing up the call chain to catch the exception and it gets thrown away. So definitely use `await send()` and look into why you get the exception. – Hans Kilian Jun 14 '21 at 07:49
  • 1
    `Main()` isn't waiting for `send()` to complete. You need to change your `Main` method to be `async` and `await send()`. – Martin Costello Jun 14 '21 at 07:51
  • I agree with everything mentioned above. You should definitely `await send()`. Also, since you are using threading you should consider what you expect when several threads try to write to the same file. Take a look at [this](https://stackoverflow.com/a/23526392/4949005) answer. – smoksnes Jun 14 '21 at 07:55
  • @HansKilian Ok. I thought it may be something about my definations and methods structure, so I'll keep digging about the exception with await send(), If I could handle it I'll post it here. Thanks a lot. – Amirali Sam Jun 14 '21 at 07:59
  • 1
    Also worth adding `catch (Exception ex)` and set brakepoints on it. – Genusatplay Jun 14 '21 at 07:59
  • @MartinCostello my `Main()` is async and `await send()` gives me a exception, I am trying to figure the exception, If I could find anything I'll update the post. Thanks a lot for your comment. – Amirali Sam Jun 14 '21 at 08:00
  • 1
    You always get exception, but when you not await it - you not see exception. – Genusatplay Jun 14 '21 at 08:01
  • @smoksnes Yes I am going to use `await send()` and find the exception. About the rest of your comment, I just simulate my code for better understanding, otherwise I have another Data Access method which will `Deserialize` the response and insert it to my database. Thanks for your comment. – Amirali Sam Jun 14 '21 at 08:03
  • @Genusatplay Your second comment clears my mind! Thanks a lot. I'll try to catch it and if I'll update the post later. Thanks again. – Amirali Sam Jun 14 '21 at 08:05
  • @dev.amirali You create `HttpClient`? There is no client creation in the presented code. – Genusatplay Jun 14 '21 at 08:05
  • @Genusatplay Yes I have. `private static HttpClient req { get; set; }` It is above `send_call()` method. – Amirali Sam Jun 14 '21 at 08:11
  • 1
    It's not create, you need `private static HttpClient req { get; set; } = new HttpClient();` (if you use new C# version). Or `req = new HttpClient();` on programm start. – Genusatplay Jun 14 '21 at 08:23
  • @Genusatplay That is correct, I thought it would work because in other solutions I used just `{ get; set; }` and I could use `PostAsync`. Anyway, thanks a lot. – Amirali Sam Jun 14 '21 at 09:34

1 Answers1

1

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();
}
Patrick Magee
  • 2,951
  • 3
  • 33
  • 50