class Program
{
static void Main(string[] args)
{
Class1 testcla = new Class1();
testcla.test();
}
}
class Class1
{
public void test()
{
test1();
}
public async void test1()
{
await test2();
}
public async Task<string> test2()
{
WebClient testwc = new WebClient();
var content = await testwc.DownloadStringTaskAsync("www.yahoo.com");
return content;
}
}
Hi,
i need wait the DownloadStringTaskAsync finished download the content, however when it execute to the line, it exit without any error.
Kindly advice
Try below code. As mentioned by #Dispersia, the url should contain http, https, ftp, etc.
You code has to wait for the async task to finish. For a starter, below description will help you to understand async.
Look at main() method, it just runs a task and that's all. The main() do not depend on any of the value of the result of async task, it ends and application is closed. Async task i.e. DownloadStringTaskAsync() takes much time to complete but by the time result is received from the WebClient, main method finishes it execution and application closes. Hence you will never see any result.
I have made a change to the main function to wait until enter is pressed. Wait for the DownloadStringTaskAsync to finish you will see content length in the output window. Then you can press enter key
static void Main(string[] args)
{
Class1 testcla = new Class1();
testcla.test();
Console.WriteLine("Wait for async task to finish.");
Console.ReadLine();
}
class Class1
{
public void test()
{
test1();
}
public async void test1()
{
await test2();
}
public async Task<string> test2()
{
try
{
WebClient testwc = new WebClient();
var content = await testwc.DownloadStringTaskAsync("http://www.yahoo.com");
Console.WriteLine("Length of content received: " + content.Length.ToString());
return content;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return null;
}
finally
{
Console.WriteLine("Async task done. Press enter to exit.");
}
}
}
Related
This question already has an answer here:
async Task vs async void
(1 answer)
Closed 3 years ago.
How would I make the main thread wait until DisplayAdd has displayed the output? If I add a Console.Read() at the end, everything works but is there another way to tell the main thread to wait until Calculate() has finished?
namespace TestDelegate
{
public class Add
{
public delegate void SendResult(int i);
public SendResult WhereToSend;
public async void Calculate (int number)
{
Console.WriteLine("Entered");
int result = number + number;
await Task.Delay(4000);
WhereToSend (result);
// Console.Read();
}
}
}
namespace TestStuff
{
class Program
{
static void Main(string[] args)
{
Add obj = new Add();
Console.WriteLine("Started Calculating");
obj.Calculate(10);
obj.WhereToSend = DisplayAdd;
}
static void DisplayAdd(int value)
{
Console.WriteLine(value);
}
}
}
You can define the delegate as Task return type (awaitable type). With this the method will finish before main thread terminates.
namespace TestDelegate
{
public delegate Task SendResult(int i);
public class Add
{
public SendResult WhereToSend;
public async Task Calculate (int number)
{
Console.WriteLine("Entered");
int result = number + number;
await WhereToSend (result);
}
}
}
namespace TestStuff
{
class Program
{
static void Main(string[] args)
{
Add obj = new Add();
obj.WhereToSend = DisplayAdd;
Console.WriteLine("Started Calculating");
obj.Calculate(10).Wait();
}
static async Task DisplayAdd(int value)
{
// Some awaitable operation like below as per your business logic
await Task.Delay(1);
Console.WriteLine(value);
}
}
}
In above program, I've changed the definition of Calculate method to async Task so that it can be marked for Waitable. The async void method are primarily used for UI events hanlder or fire and forget method.
Please check this dotnetfiddle which demonstrates the scenario.
I have a console app that instantiates a WeatherClientManager class.
The main thread in the console app requests current weather status in the WeatherClientManager class, but the WeatherClientManager class continuously receives data from a server.
In code:
public static void Main(string [])
{
Program p = new Program();
Task.Run(()=>p.RunLoop());
}
class Program{
WeatherClientManager wcM;
public void RunLoop()
{
wcM = new WeatherClientManager ();
await wcM.InitiateConnection().ConfigureAwait(false);
}
}
class WeatherClientManager
{
public async Task<bool> InitiateConnection()
{
TCPClient tcpClient = new TcpClient(GetTCPDetailsFromConfig())
await tcpClient.ConnectAsync()
CancellationTokenSource cts = new CancellationTokenSource();
if(tcpClient.Connected)
{
Task.Run(()=>ReceiveTask(cts.Token));
Task.Run(()=>SendKeepAlive(cts.Token));
return true;
}
return false;
}
private void ReceiveTask(CancellationToken t)
{
try{
networkStream.Receive(..) // throws exception
}
catch(Exception e)
{
Stop(e);
}
}
private void SendKeepAlive(CancellationToken t)
{
while(!t.IsCancellationRequested)
{
try{
networkStream.Write(..) // throws exception
}
catch(Exception e)
{
Stop(e);
}
}
}
private void Stop(Exception e )
{
log.Error(e);
e.Cancel();
}
}
One of many crap ideas I have is:
Task.Run( () =>
{
while(true)
{
var t1 = Task.Run(()=>ReceiveTask(cts.Token));
var t2= Task.Run(()=>SendKeepAlive(cts.Token));
try{
Tasks.WhenAny(); // should block
}
catch(Exception e)
{
}
finally{
Cleanup();
InitiateConnections();
}
}
}
But I hate the idea of spinning a task to control two sub tasks. My problem is where and how to re-initiate the connection. Any ideas?
EDIT:
I've updated the code such that WeatherClientManager has a OnDisconnectDetected event. So the Program.cs class subscribes like so:
weatherServerManager.OnDisconnectDetected += HandleDisconnectDetection
public async void HandleDisconnectDetection()
{
wsM = new WeatherClientManager ();
wsM.InitiateConnection().ConfigureAwait(false);
}
private void SendKeepAlive(CancellationToken t)
{
while (...)
{
try{}
catch(Exception e)
{
OnDisconnectDetected?.Invoke();
}
}
}
When the handler is invoked by the WeatherClientManager it creates a new task that should continue in a different context. The KeepAlive task should exit then.
Still feels hacky but ideas welcome!
As a general rule, I prefer composition of methods over raising events. In particular, avoid the Task.Run-based fire-and-forget.
In the case of asynchronous sockets, I think it makes sense to give each socket a main loop:
class WeatherClientManager
{
public async Task MainLoop()
{
TCPClient tcpClient = new TcpClient(GetTCPDetailsFromConfig())
await tcpClient.ConnectAsync();
CancellationTokenSource cts = new CancellationTokenSource();
var receiveTask = Task.Run(()=>ReceiveTask(cts.Token));
var keepaliveTask = Task.Run(()=>SendKeepAlive(cts.Token));
await Task.WhenAll(receiveTask, keepaliveTask);
}
}
These can then be composed into the main program's main loop:
class Program
{
public async Task RunLoop()
{
while (true)
{
wcM = new WeatherClientManager();
await wcM.MainLoop();
}
}
}
which in turn is composed into Main:
public static void Main(string [])
{
Program p = new Program();
p.RunLoop().GetAwaiter().GetResult();
}
By avoiding fire-and-forget, you're ensuring that your code will always observe all exceptions. Ignoring tasks is occasionally okay but usually a mistake.
I'm running a C# console application with .NET 4.5.1. When I run the following function the udpClient.ReceiveAsync() call below silently terminates the program with no exception. How do I debug this?
public async void Run()
{
try
{
var armIpAddress = IPAddress.Parse("239.1.11.1");
using (var udpClient = new UdpClient())
{
udpClient.ExclusiveAddressUse = false;
var ipEndPoint = new IPEndPoint(IPAddress.Any, 12020);
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.ExclusiveAddressUse = false;
udpClient.Client.Bind(ipEndPoint);
udpClient.JoinMulticastGroup(armIpAddress);
while (true)
{
var result = await udpClient.ReceiveAsync();
//...
}
}
catch (Exception x)
{
Console.WriteLine(x.Message);
}
}
The call to await udpClient.ReceiveAsync() is not terminating the program nor it is silently failing.
Given that this is happening, I assume you have something like this:
public static void Main(string[] args)
{
...
Run();
}
In an async void method, control is returned to the parent as soon as an await call is reached, so the flow of the program would be something like:
public static void Main(string[] args)
{
...
var armIpAddress = IPAddress.Parse("239.1.11.1");
using (var udpClient = new UdpClient())
{
udpClient.ExclusiveAddressUse = false;
.......
while (true)
{
return;
}
}
}
So the program ends due to no further blocking code.
For this to work as you would expect, change the code to this:
public static void Main(string[] args)
{
...
Run().Wait();
}
public async Task Run() { ... }
Not sure about the calling method, but with the given infomation, I would suggest the following article that has best practices around async await by #Stephen Cleary
It says to avoid async void and I am pasting an excerpt here from the article for quick reference
Async void methods can wreak havoc if the caller isn’t expecting them to be async. When the return type is Task, the caller knows it’s
dealing with a future operation; when the return type is void, the
caller might assume the method is complete by the time it returns.
This problem can crop up in many unexpected ways.
Exceptions from an Async Void Method Can’t Be Caught with Catch
I was creating a puzzle with a bit of information in different sources to create this...
System.Threading.Thread th;
th = new System.Threading.Thread(new System.Threading.ThreadStart(() =>
{
InvokeOnMainThread(() =>
{
lbMemFree.Text = "memory free: " + NSProcessInfo.ProcessInfo.PhysicalMemory; // this works!
});
}));
th.Start();
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
th.Sleep(500); // delay execution for 500 ms
// more code
});
The idea is to create something that update the label times in time. In this scenario: 500ms.
But the th.Sleep(500) don't allow the app to compile. It's says: Error CS0176: Static member System.Threading.Thread.Sleep(int) cannot be accessed with an instance reference, qualify it with a type name instead (CS0176).
You can use async await for this.
Interval
public class Interval
{
public static async Task SetIntervalAsync(Action action, int delay, CancellationToken token)
{
try
{
while (!token.IsCancellationRequested)
{
await Task.Delay(delay, token);
action();
}
}
catch(TaskCanceledException) { }
}
}
usage (e.g. Console Application for demo)
class Program
{
static void Main(string[] args)
{
var cts = new CancellationTokenSource();
Interval.SetIntervalAsync(DoSomething, 1000, cts.Token);
Console.ReadKey(); // cancel after first key press.
cts.Cancel();
Console.ReadKey();
}
public static void DoSomething()
{
Console.WriteLine("Hello World");
}
}
Use the CancellationTokenSource to cancel the execution of the interval.
I would have a async call to a function as following:
I'll call a method from the main method, this function should be async, how I do this?
A little example:
private static void Main(string[] args)
{
StartDoingNothingAsync();
Console.WriteLine("test");
Console.Read();
}
private static async void StartDoingNothingAsync()
{
for (var i = 0; i < 5000; i++)
{
//do something
}
Console.WriteLine("leaved");
}
I would first the output "test", before "leaved", how can I practice this?
The simplest option would be to introduce a delay into your async method:
private static async void StartDoingNothingAsync()
{
await Task.Delay(1000);
// This will be called on a thread-pool thread
Console.WriteLine("leaved");
}
That won't guarantee that test will be printed before leaved, but it seems very likely. If you actually want a guarantee, you'd have to pass something into StartDoingNothingAsync that you then signal after printing test... but it's not really clear what you're trying to achieve.
Note that async methods should almost never be void - basically that's only available to allow for async event handlers. Make the method return Task instead - that way your calling code can tell when it's completed. (Even if you don't use that fact in this case, it's a good habit to get into.)
Now that we have a bit more information about what you're trying to achieve, I would recommend not making StartDoingNothingAsync an async method - just use a task instead:
private static void Main(string[] args)
{
Task task = Task.Run(DoSomething);
Console.WriteLine("test");
task.Wait();
Console.Read();
}
static void DoSomething()
{
// Code to run on a separate thread
}
You can do it like this
private static void Main(string[] args)
{
StartDoingNothingAsync();
Console.WriteLine("test");
Console.Read();
}
private static async void StartDoingNothingAsync()
{
await Task.Run(async delegate()
{
for (var i = 0; i < 5000; i++)
{
//do something
}
Console.WriteLine("leaved");
});
}
You can use Task for that. In that case you don't need to mark your function as async:
private static void Main(string[] args)
{
new Task(StartDoingNothing).Start();
Console.WriteLine("test");
Console.Read();
}
private static void StartDoingNothing()
{
for (var i = 0; i < 5000; i++)
{
//do something
}
Console.WriteLine("leaved");
}