-1

I have a console application which is running as scheduler, and same consumes a Web API and have two sections as mentioned below

  1. Posting files to API - where i am sending some files to API to get some information from the files.
  2. Getting Response from the API- where i am receiving the response from the API which i have already send to the API previously.

So process will flow as follows. When scheduler runs initially, I will be sending some files (example A,B and C) to the API. And API will time some time to process the files.

So next time when scheduler runs it will post some more files D,E,F etc and will try to get the response of A,B,C

skeleton of code as follows

 static void Main(string[] args)
        {                               
            //"starting Posting files to API";
            PostDatas(ds);                

            //"Getting Response from the API";
            GetResponseXML(ds);               

        }
        public static void PostDatas(DataSet ds)
        {
            var client = new HttpClient();
            foreach (DataRow dr in ds.Tables[0].Rows)
            {
                //post the files 
                var response = client.PostAsync(URL, ReqClass, bsonFormatter).Result;

            }
        }
        public static void GetResponseXML(DataSet ds)
        {
            var clientResponse = new HttpClient();
            foreach (DataRow dr in ds.Tables[1].Rows)
            {
                //get the response.
                var response = clientResponse.PostAsync(URL,ReqClass, bsonFormatter).Result;

            }
        }
    }

Here all the process are in synchronous way which is causing too much time.

I want to make the posting process and getting response in asynchronous way. posting multiple files together as well as getting response for multiple files parallel

How can i achieve this? use the threading concept or use the async and await concept or TPL(Task parallel library). What changes i should perform in above code to make it work asynchronously.

Please help with samples.

AcAnanth
  • 765
  • 3
  • 19
  • 53

1 Answers1

1

You need to create an async version of your Main then call each method in parallel, then await the results. I'm blocking on your void Main here as I presume that's what you want? you could add an additional thread pool thread here but I doubt you'll get much advantage out of it. I've only done one method below as the other is basically the same:

static void Main(string[] args)
{
    MainAsync(args).GetAwaiter().GetResult();
}


static async Task MainAsync(string[] args)
{
    DataSet ds = new DataSet();
    /*logic for getting dataset values.table0 contains posting file details
    and Table1 contains details of files which need response*/


    //"starting Posting files to API";
    await PostDatas(ds);
    //"Ending Posting files to API";

    //"Getting Response from the API";
    await GetResponseXML(ds);
    //"Ending Getting Response from the API";

}
public async static Task PostDatas(DataSet ds)
{
    var client = new HttpClient();
    List<Task<HttpResponseMessage>> tasks = new List<Task<HttpResponseMessage>>();
    foreach (DataRow dr in ds.Tables[0].Rows)
    {

        //post the files 
        tasks.Add(client.PostAsync(URL, ReqClass, bsonFormatter));

    }

    await Task.whenAll(tasks);
    foreach(var response in tasks)
    {
         //you can access Result here because you've awaited 
         //the result of the async call above
         HttpResponseMessage message = response.Result;
         //etc.

    }
}

In C# 7.0 you can do away with the .GetAwaiter().GetResult(); and just declare your Main async; static async Task Main(string[] args)

Be aware that DataSet is not threadsafe. So I wouldn't recommend you altering that class using this method.

If your not bothered about waiting for your post before running Getresponse you could also add additional parralisation:

static async Task MainAsync(string[] args)
{
    DataSet ds = new DataSet();
    /*logic for getting dataset values.table0 contains posting file details
    and Table1 contains details of files which need response*/

    List<Task> tasks = new List<Task>(2);
    //"starting Posting files to API";
    tasks.Add(PostDatas(ds));
    //"Ending Posting files to API";

    //"Getting Response from the API";
    tasks.Add(GetResponseXML(ds));
    //"Ending Getting Response from the API";

    await Task.WhenAll(tasks);
}
Liam
  • 27,717
  • 28
  • 128
  • 190
  • `.GetAwaiter().GetResult();` is a *blocking call* equivalent to `.Result`. The only difference is that it doesn't wrap any exceptions in an `AggregateException` – Panagiotis Kanavos Aug 07 '18 at 10:24
  • I'm presuming that the OP wants to block at this point? I could threadpool it I suppose – Liam Aug 07 '18 at 10:24
  • It's not quite equiverlant either [`Note the use of GetAwaiter().GetResult(); this avoids the AggregateException wrapping that happens if you use Wait() or Result.`](https://stackoverflow.com/a/9212343/542251) – Liam Aug 07 '18 at 10:26
  • the code and wording are a bit mixed up. You should probably put the C# 7 code at the *bottom* of the answer then and write `just declare your Main void`. Put the `async Task Main()` version at the top – Panagiotis Kanavos Aug 07 '18 at 10:26
  • I have declared my `main void`? I've just added an additional non async main – Liam Aug 07 '18 at 10:27
  • You write `You need to make your Main async then call each method in parallel,` then post a `void Main()` – Panagiotis Kanavos Aug 07 '18 at 10:29
  • @Liam: First time i will post the data and then API will take atleast 30mnt give the response back thats why i splitted the post and getrespone into two separate – AcAnanth Aug 07 '18 at 10:55
  • Mean while if i got any other file i should post again – AcAnanth Aug 07 '18 at 10:56
  • which is fine, just use the first version without the additional `WhenAll` – Liam Aug 07 '18 at 11:01