-1

I've tried to have a look online for an answer to this and I'm not finding anything.

This method I have looks fine, and seems to follow the general flow of how async post calls work in c#.

     private static async Task<HttpResponseMessage> GetGeocodingAsync(string URL, string JSONQuery)
    {
        using (HttpClient client = new HttpClient())
        {
            using (HttpResponseMessage r = await client.PostAsync(URL, new StringContent(JSONQuery, Encoding.UTF8, "application/json")))
            {
                return r;
            }
        }
    }

    public Task<HttpResponseMessage> GetGeocoding(string TTURL, string JSONQuery)
    {
        return GetGeocodingAsync(TTURL, JSONQuery);
    }

When I check my syntax and in my IDE however when I run the application it gets as far as line 5 then the application just ends with a code 0 (exited with code 0 (0x0).).

I've done a lot of web research and can't find an answer for this. Am I missing something fundamental here?

I understand that I have to use an private static async for the actual post part, then I can call this method from a non-static non-async method, and in my main class I can process the response that I get like this:

   Task<HttpResponseMessage> x = TTConnect.GetGeocoding(TTConnect.GetTTConnectionURL(),JSONQuery);

I'm trying to send some data in JSON format using POST, check the response by parsing it, and pull down the response to the POST.

I'm using the TomTom Batch API

Any thoughts or suggestions would be welcome.

  • Are you `await`ing the all to this method? If not you'll just be creating a `Task` that will be garbage collected and never have a chance to run. – DavidG Jan 21 '18 at 02:43

2 Answers2

1

I believe you're problem is the way you're using async / await and the Task in general.

This line

Task<HttpResponseMessage> x = TTConnect.GetGeocoding(TTConnect.GetTTConnectionURL(),JSONQuery);

... needs to either be in an async method and call await or .Result on the task. x is not the result of the task but the task itself. Task is just a managed thread right? What you're doing is assigning x the thread so to speak and not the result of what the thread has done (...only it's not a thread it's a task but anyway).

In order to get x to be the result of the task you would do something like...

var x = await TTConnect.GetGeocoding(TTConnect.GetTTConnectionURL(),JSONQuery);

or

var x = TTConnect.GetGeocoding(TTConnect.GetTTConnectionURL(),JSONQuery).Result;

Another thing to point out is that your private static GetGeocodingAsync method is the same as your public GetGeoCoding method. You can put the .Result in the public method return line and it will work. OR you can just delete it and use the GetGeocodingAsync method with the .Result or await it.

Anyway, the point is you're not using tasks correctly and I think there's just a little bit of confusion on how / what a task is and how to properly use it normally or with async await. Not a big deal either. Just fix the code to call it properly and it will work properly (either throwing errors or not for example.)

Michael Puckett II
  • 6,586
  • 5
  • 26
  • 46
  • I suggest removing the mention of threads here - I don't believe it's accurate and it just serves to confuse. A Task is simply an object that represents an operation that will compete sometime in the future. – Rob Smith Jan 21 '18 at 11:02
  • Thanks Michael, I edited my app to reflect the changes you suggested, I removed the confusing methods and changed it so that I use the GetGeocodingAsync method directly. Still getting a 400 error but I am happy I am making progress. I'm not a professional programmer, just an enthusuasit so going to read more about await and it's dynamics so I get what's going on. – Omar Sarhan Jan 21 '18 at 13:06
  • @RobSmith People understand threads and I just used it to help explain tasks and a task is a managed thread and still comes from a thread pool and works from the core just the same. – Michael Puckett II Jan 22 '18 at 01:42
  • @OmarSarhan Ok, the 400 error sounds like it's related the ```client.PostAsync``` method. I'm glad you're making progress. Keep up the good work :) – Michael Puckett II Jan 22 '18 at 02:02
  • @Michael I understand the temptation to use the analogy. "A Task is a managed thread" is simply not true though. A _continuation_ of an _async_ method will be scheduled to run on a thread, but that's really all you can say in general. Especially in the case for async http tasks, where there is no thread doing any work when waiting for the network. If the OP leaves the question thinking his Task is being _run_ by a thread somewhere, they will not have learned anything. – Rob Smith Jan 22 '18 at 08:29
  • @RobSmith I had a read alright and I got what Michael was saying, off topic but i figured a thread was something you could set run and go ahead and something else. I got my code to return the valid data with a valid status code , and when I snoop on the data with Fiddler, the response looks perfect. Now my next hurdle is that my response is getting disposed of. – Omar Sarhan Jan 23 '18 at 01:10
1

If this is a simple console exe, then it is indeed the case that an incomplete await in the primary thread will usually terminate the exe. This is because await returns to the calling code, and if you exit Main(), your thread exits. If all your non-background threads exit: your app exits.

In the latest C# versions, you can do:

async static Task Main() {...}

instead of:

static void Main() {...}

and it will behave correctly for you. Alternatively, you can do something like:

static void Main() {
    Main2().GetAwaiter().GetResult();
}
async static Task Main2() {...} // your code here

The other possibility is that you have an unawaited exception on a background thread, due to not await-ing all your tasks. Threads hate faulting, and an unhandled exception at the top of a thread will kill your app. If this is the problem: await your tasks, or add a continuation that ignores the error if you really don't care about success. For example:

    static void FireAndForget(this Task task)
    {
        if (task.IsCompleted) return;
        task.ContinueWith(t =>
        {
            try
            { // show it that we checked
                GC.KeepAlive(t.Exception);
            } catch { }
        }, TaskContinuationOptions.OnlyOnFaulted);
    }
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900