HttpClient.PostAsync knocks out the app with exit code 0 - c#

Everything was working today until it stopped... Below is the minimum source code (I'm using VS 2012 Update 1, .Net 4.5). When I run it, app exits upon calling client.PostAsync() and so it never reaches Console.ReadLine(). Same in debugger, no exception, nothing, exit code 0.
I tried rebooting machine, restarting VS2012 - nothing works.
Again, everything was running today, not sure what changed (no software has been installed etc, all other network apps still work).
Any ideas? I think I'm loosing my mind.
class Program
{
static void Main(string[] args)
{
Run();
}
private async static void Run()
{
using (var client = new System.Net.Http.HttpClient())
{
var headers = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("submit.x", "48"),
new KeyValuePair<string, string>("submit.y", "15"),
new KeyValuePair<string, string>("submit", "login")
};
var content = new FormUrlEncodedContent(headers);
HttpResponseMessage response = await client.PostAsync("http://www.google.com/", content);
Console.ReadLine();
}
}
}

Your problem is that a program normally exits when its Main() method finishes. And your Main() finishes as soon as you hit the await in Run(), because that's how async methods work.
What you should do is to make Run() into an async Task method and then wait for the Task in your Main() method:
static void Main()
{
RunAsync().Wait();
}
private static async Task RunAsync()
{
…
}
In C# 7.1+ you should use async Main instead:
static async Task Main()
{
await RunAsync();
}
private static async Task RunAsync()
{
…
}
Few more notes:
You should never use async void methods, unless you have to (which is the case of async event handlers).
Mixing await and Wait() in a GUI application or in ASP.NET is dangerous, because it leads to deadlocks. But it's the right solution if you want to use async in a console application.

Related

what is the cause for my console app exiting with code 0?

I'm trying to call a site via its url to build a webscraper, but when i try to grab the items from the awaited url my application stops and brings up this message:
blablah.exe (process 1512) exited with code 0.
To automatically close the console when debugging stops, enable Tools->Options->Debugging->Automatically close the console when debugging stop
I dont think this is a code issue, perhaps something with my visual studio debugger? for the life of me can't see what it is.
This is a .net core command line app
Some code just in-case
static void Main(string[] args)
{
GetHtmlAsync();
}
private static async void GetHtmlAsync()
{
var url = "https://blahblah.com";
var client = new HttpClient();
var html = await client.GetStringAsync(url);
var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(html);
var newsList = htmlDoc.DocumentNode.Descendants("table")
.Where(node => node.GetAttributeValue("class","")
.Equals("itemList")).ToList();
Console.WriteLine(newsList);
Console.Read();
}
}
when debugging it never even reaches:
var htmlDoc = new HtmlDocument();
any ideas?
There are a couple problems here
1) When you call GetHtmlAsync() you are not awaiting it, meaning your application continues to run the code after it (of which there is none), leading to the app exiting
2) You should avoid async void except for event handlers, instead return async Task
Modified code might look like this
static async Task Main(string[] args)
{
await GetHtmlAsync();
}
private static async Task GetHtmlAsync()
{
//Do stuff
}
Note that in order to use async Task Main you need to be using at least C# 7.1
The reason it's returning 0 (zero), success, is because it exited without error.
Change the method to:
private static async Task GetHtmlAsync()
And call it like this:
GetHtmlAsync().Wait();
The method will run synchronously, but the app does anyway, as written.

console.writeline within Task does not work

I am learning task aysny based programing and cannot get to make this code work. The console prints the message only once and then disappears.
if I remove the read line and run the program(not debug mode) the console just appears with message saying press a key to continue. When I debug and put the debugger in console.write then it works fine for some time and then the console window disappears and restarts again. If I use for loop <10000 instead of while then also the behaviors is same
Could you please suggest what I am doing wrong.
static void Main(string[] args)
{
multitasker();
}
static async void multitasker()
{
Task task1 = new Task(PrintMessageA);
task1.Start();
await task1;
}
static void PrintMessageA()
{
while(true)
{
Console.WriteLine("Message from A");
Console.ReadLine();
}
}
Your main thread does not block and thus is exiting immediately. You would have to go "await all the way" in a sense and await multitasker as well, but you can't actually do that as seen later.
So first you return a task in multitasker
static async Task multitasker()
{
Task task1 = new Task(PrintMessageA);
task1.Start();
await task1;
}
The problem is you cannot make Main() (the entry point) async, so instead you would need to block that thread by instead calling Wait() on the returned Task
static void Main(string[] args)
{
multitasker().Wait();
}

console app main method return string from async Task error [duplicate]

This question already has answers here:
Can't specify the 'async' modifier on the 'Main' method of a console app
(20 answers)
Closed 5 years ago.
I have this simple code:
public static async Task<int> SumTwoOperationsAsync()
{
var firstTask = GetOperationOneAsync();
var secondTask = GetOperationTwoAsync();
return await firstTask + await secondTask;
}
private async Task<int> GetOperationOneAsync()
{
await Task.Delay(500); // Just to simulate an operation taking time
return 10;
}
private async Task<int> GetOperationTwoAsync()
{
await Task.Delay(100); // Just to simulate an operation taking time
return 5;
}
Great. This compiles.
But let’s say I have a console application and I want to run the code above (calling SumTwoOperationsAsync()).
static void Main(string[] args)
{
SumTwoOperationsAsync();
}
But I've read that (when using sync) I have to sync all the way up and down:
Does this mean that my Main function should be marked as async?
Well, it can't be because there is a compilation error:
an entry point cannot be marked with the 'async' modifier
If I understand the async stuff , the thread will enter the Main function → SumTwoOperationsAsync → will call both functions and will be out. But until the SumTwoOperationsAsync
What am I missing?
In most project types, your async "up" and "down" will end at an async void event handler or returning a Task to your framework.
However, Console apps do not support this.
You can either just do a Wait on the returned task:
static void Main()
{
MainAsync().Wait();
// or, if you want to avoid exceptions being wrapped into AggregateException:
// MainAsync().GetAwaiter().GetResult();
}
static async Task MainAsync()
{
...
}
or you can use your own context like the one I wrote:
static void Main()
{
AsyncContext.Run(() => MainAsync());
}
static async Task MainAsync()
{
...
}
More information for async Console apps is on my blog.
Here is the simplest way to do this
static void Main(string[] args)
{
Task t = MainAsync(args);
t.Wait();
}
static async Task MainAsync(string[] args)
{
await ...
}
As a quick and very scoped solution:
Task.Result
Both Task.Result and Task.Wait won't allow to improving scalability when used with I/O, as they will cause the calling thread to stay blocked waiting for the I/O to end.
When you call .Result on an incomplete Task, the thread executing the method has to sit and wait for the task to complete, which blocks the thread from doing any other useful work in the meantime. This negates the benefit of the asynchronous nature of the task.
notasync
My solution. The JSONServer is a class I wrote for running an HttpListener server in a console window.
class Program
{
public static JSONServer srv = null;
static void Main(string[] args)
{
Console.WriteLine("NLPS Core Server");
srv = new JSONServer(100);
srv.Start();
InputLoopProcessor();
while(srv.IsRunning)
{
Thread.Sleep(250);
}
}
private static async Task InputLoopProcessor()
{
string line = "";
Console.WriteLine("Core NLPS Server: Started on port 8080. " + DateTime.Now);
while(line != "quit")
{
Console.Write(": ");
line = Console.ReadLine().ToLower();
Console.WriteLine(line);
if(line == "?" || line == "help")
{
Console.WriteLine("Core NLPS Server Help");
Console.WriteLine(" ? or help: Show this help.");
Console.WriteLine(" quit: Stop the server.");
}
}
srv.Stop();
Console.WriteLine("Core Processor done at " + DateTime.Now);
}
}

How to correctly write async method?

So I am trying to learn the basics of using 'async' and 'await' in C#, but I am not sure what I am doing wrong here. I am expecting the following output:
Calling DoDownload
DoDownload done
[...output here...]
But I don't get the output of the download, and I also expect "done" but that takes a while. Shouldn't that be output immediately? Also, I can't seem to get the string result either. Here is my code:
namespace AsyncTest
{
class Program
{
static void Main(string[] args)
{
Debug.WriteLine("Calling DoDownload");
DoDownloadAsync();
Debug.WriteLine("DoDownload done");
}
private static async void DoDownloadAsync()
{
WebClient w = new WebClient();
string txt = await w.DownloadStringTaskAsync("http://www.google.com/");
Debug.WriteLine(txt);
}
}
}
To get the behavior you want you need to wait for the process to finish before you exit Main(). To be able to tell when your process is done you need to return a Task instead of a void from your function, you should never return void from a async function unless you are working with events.
A re-written version of your program that works correctly would be
class Program
{
static void Main(string[] args)
{
Debug.WriteLine("Calling DoDownload");
var downloadTask = DoDownloadAsync();
Debug.WriteLine("DoDownload done");
downloadTask.Wait(); //Waits for the background task to complete before finishing.
}
private static async Task DoDownloadAsync()
{
WebClient w = new WebClient();
string txt = await w.DownloadStringTaskAsync("http://www.google.com/");
Debug.WriteLine(txt);
}
}
Because you can not await in Main() I had to do the Wait() function instead. If this was a application that had a SynchronizationContext I would do await downloadTask; instead and make the function this was being called from async.
You are calling DoDownloadAsync() but you don't wait it. So your program going to the next line. But there is another problem, Async methods should return Task or Task<T>, if you return nothing and you want your method will be run asyncronously you should define your method like this:
private static async Task DoDownloadAsync()
{
WebClient w = new WebClient();
string txt = await w.DownloadStringTaskAsync("http://www.google.com/");
Debug.WriteLine(txt);
}
And in Main method you can't await for DoDownloadAsync, because you can't use await keyword in non-async function, and you can't make Main async. So consider this:
var result = DoDownloadAsync();
Debug.WriteLine("DoDownload done");
result.Wait();

HttpClient GetStringAsync - It never comes back

New ASP.NET Web API HttpClient has been giving me some strange results. Here is my code:
class Program {
static async void Main(string[] args) {
var address = "http://localhost:3895/api/urls";
Console.WriteLine(await getStringAsync(address));
Console.ReadLine();
}
public static async Task<string> getStringAsync(string uri) {
var httpClient = new HttpClient();
return await httpClient.GetStringAsync(uri);
}
}
This never comes back and the console suddenly appears and disappears. When I change the code as below, it works as it is supposed to:
static void Main(string[] args) {
var address = "http://localhost:3895/api/urls";
Console.WriteLine(getString(address));
Console.ReadLine();
}
public static string getString(string uri) {
var httpClient = new HttpClient();
return httpClient.GetStringAsync(uri).Result;
}
Any idea on what would be the issue?
async on Main is disallowed in the VS11/.NET 4.5 compiler, so I'm assuming you're using the Async CTP. If using .NET 4.5 is at all an option, do make the switch.
That aside, the reason it doesn't work is because async, or more generally, tasks, rely on being able to signal some way for the remainder of the code to be executed. It works with .Result because the code runs synchronously, so the problem doesn't apply.
There is no built-in support for console applications, because they don't normally use message loops in the way that for example WinForms does, but you can look at Microsoft Visual Studio Async CTP\Samples\(C# Testing) Unit Testing\AsyncTestUtilities, notably GeneralThreadAffineContext.cs, to get a basic example that works in console applications too.

Categories

Resources