How to call on async Task function from Void class? - c#

How to call on async Task function from Void class?
Let's say I got this built up like this,
I Want to call the methods in Run() in sync, but in the DoSomeStuffAsync and DoSomeStuffAsync 2
It requires await on some functions that has async awaitable functions.
My Question is, how can I in DoTask1 e.g. make the task to run sync? Like now the tasks just starts it and it doesn't wait until it finish at all.
static void Main(string[] args)
{
Run();
}
public void Run()
{
DoTask1();
DoTask2();
}
public void DoTask1()
{
var tasks = Task.Run(async () =>
{
await DoSomeStuffAsync();
await DoSomeStuffAsync2();
});
Task.WaitAll(tasks);
}
public void DoTask2()
{
var tasks = Task.Run(async () =>
{
await DoSomeStuffAsync();
await DoSomeStuffAsync2();
});
Task.WaitAll(tasks);
}
private async Task DoSomeStuffAsync(int daysBack)
{
try
{
var data= await GetData();
var objj = GenerateObjects();
await InsertToDb(objj ));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private async Task DoSomeStuffAsync2(int daysBack)
{
try
{
var data= await GetOtherData();
var objj = GenerateObjects();
await InsertToDb(objj ));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

The Console app static void Main() is calling on the Run() function.
You have a couple of options. For both of the options below, you should first make your Run method properly asynchronous (i.e., async Task).
If this is a .NET Core project, then option A is to make Main an async Task method. Then you can use async all the way.
If not, then you can have a single blocking call. I recommend that this go into your Main method, as such:
static void Main()
{
Run().GetAwaiter().GetResult();
}

Async void is a bad choice, generates compiler warnings, if an exception is uncaught there, your application is dead and you won’t probably have a proper call stack to debug with. But if you want, you already have the solution just
call directly the async task method. And wrappe it in a exception catcher
static void Main(string[] args)
{
Task callTask = Task.Run(() => Run());
callTask.Wait();
}
public async Task Run()
{
await DoSomeStuffAsync();
}

Related

Why I couldn't catch the exception in async function that has void return type?

static void Main(string[] args) {
try {
var a = MyMethodAsync();
a.Wait(); // calling Wait throw an AggregateException
}
catch (Exception e) {
Console.WriteLine("Catch");
}
Console.ReadLine();
}
static async Task<String> MyMethodAsync() {
String s = await TestThrowException();
return s;
}
static Task<String> TestThrowException() {
return Task.Run(() => {
throw new DivideByZeroException();
return "placeholder"; // return statement is needed for the compilier to work correctly
});
}
The code above works, the catch block in Main method can catch the AggregateException exception (originate from TestThrowException and get converted into AggregateException).
But if I have the code like this:
static void Main(string[] args) {
try {
MyMethodAsync();
}
catch (Exception e) {
Console.WriteLine("Catch");
}
Console.ReadLine();
}
static async void MyMethodAsync() {
await TestThrowException();
}
static Task<String> TestThrowException() {
return Task.Run(() => {
throw new DivideByZeroException();
return "placeholder";
}
then the catch block in Main method cannot catch any exception, why is that?
Any time you have async void, you're basically breaking the ability to correctly signal completion and failure; the only way it can report failure is if the exception happens immediately and before any incomplete await - i.e. synchronously. In your case, the Task.Run guarantees that this is not synchronous, hence any knowledge of the outcome and failure: is lost.
Fundamentally, never write async void (unless you absolutely have to, for example in an event-handler). In addition to the problem above, it also has known complications with some SynchronizationContext implementations (in particular the legacy ASP.NET one), which means simply invoking an async void method is enough to crash your application (at least hypothetically; the sync-context caveat applies more to library authors than application authors, since library authors don't get to choose the application execution environment).
Remove the async void. If you want to return "nothing", then you should use async Task or async ValueTask as the signature:
static async Task MyMethodAsync() {
await TestThrowException();
}
(which could perhaps also be simplified to)
static Task MyMethodAsync()
=> TestThrowException();
and:
static async Task Main(string[] args) {
try {
await MyMethodAsync();
}
catch (Exception e) {
Console.WriteLine("Catch");
}
Console.ReadLine();
}

Do nest await is the good way to run some async job intervally in parallel?

I have three different job class for different work, each of them needs to run in the background in a specified interval.
Is the following code is good in performance and clean in code style?
if not, how to fix it? I am new to c#, my dev environment is net core 3.1
class Program
{
static void Main(string[] args)
{
Method1();
Method2();
Console.ReadKey();
}
public static async Task Method1()
{
await Task.Run(() =>
{
var run = true;
for (run)
{
var c = await fetchConfigFromDBAsync()
run = c.run;
var interval = c.interval
await JobClass1.RunAsync()
Thread.Sleep(interval)
}
});
}
public static async Task Method2()
{
await Task.Run(() =>
{
for (true)
{
await JobClass2.RunAsync()
Thread.Sleep(new TimeSpan(0, 10, 4))
}
});
}
public static async Task Method3()
{
await Task.Run(() =>
{
for (true)
{
await JobClass3.RunAsync()
Thread.Sleep(new TimeSpan(1, 0, 3))
}
});
}
}
You must avoid Thread.Sleep for theses reasons. You can use Task.Delay() instead.
Then, you don't need to encapsulate your loops into Task.Run() if your async call is really an awaitable function, like sending data, commucicating with database, etc..
If your async function is more like heavy calculations, you can keep it. More explainations here.
And then, it's cleaner to wait all the infinites tasks rather than use Console.ReadLine()
static async Task Main(string[] args)
{
Task m1 = Method1();
Task m2 = Method2();
await Task.WhenAll(new[] { m1, m2 });
}
public static async Task Method2()
{
while (true)
{
await JobClass.RunAsync();
await Task.Delay(3);
}
}
public static async Task Method1()
{
while (true)
{
await JobClass.RunAsync();
await Task.Delay(3);
}
}

Why the console exits even after using await?

using System;
using System.Threading;
using System.Threading.Tasks;
namespace application
{
public class Files
{
public static Task<string> runTask()
{
return Task.Run(() =>
{
Thread.Sleep(2000);
return "Hello World!";
});
}
public static async void Hello()
{
string result = await runTask();
Console.WriteLine(result);
Console.WriteLine("Execution Ended!");
}
public static void Main(string[] args)
{
Hello();
Console.WriteLine("The Async Code Is Running Above!");
}
};
};
The above C# code just prints "The Async Code Is Running Above!" and nothing happens after that.
How can I make this print things in following order (And where I'm going wrong):
"The Async Code Is Running Above!"
"Hello World!"
"Execution Ended!"
Thankyou!
There are a two main points in your question. First, don't use Thread.Sleep inside asynchronous methods, use Task.Delay instead. Second, you can make Main method async as well and return a Task to get an expected behavior (it's possible starting from C# 7.1)
public static Task<string> runTask()
{
return Task.Run(async () =>
{
await Task.Delay(2000);
return "Hello World!";
});
}
public static async Task Hello()
{
string result = await runTask();
Console.WriteLine(result);
Console.WriteLine("Execution Ended!");
}
static async Task Main()
{
await Hello();
Console.WriteLine("The Async Code Is Running Above!");
}
Avoid using void async methods, try returning tasks always. Check this post for more details async-await-when-to-return-a-task-vs-void
class Files
{
static void Main(string[] args)
{
Task t = Hello();
Console.WriteLine("The Async Code Is Running Above!");
//Wait for the task to complete
//Dont use this code in UI applications which will cause blocking
t.Wait();
//keep the application open
Console.ReadLine();
}
public static Task<string> runTask()
{
return Task.Run(async () =>
{
await Task.Delay(2000);
return "Hello World!";
});
}
public static async Task Hello()
{
string result = await runTask();
Console.WriteLine(result);
Console.WriteLine("Execution Ended!");
}
}

Task.WaitAll() hangs in console application

I have a console application in which I need to retrieve some data from 4 different sites. I placed each HTTP request in a task and I wait for them all to complete.
It was working when I only had to get data from 2 sites. but then I needed to add other sources of data and when adding 3 or more requests, the Task.WaitAll() hangs.
Below is my code.
The reason I ended up using Task.WaitAll() was because I need to stop and prevent the console application from exiting - i.e. I need to perform other tasks only after all the HTTP requests come back with data.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static Task[] tasks = new Task[3];
static void Main(string[] args)
{
try
{
Run();
}
catch (System.Exception ex)
{
}
}
public static async void Run()
{
//works when using one or two tasks
tasks[0] = HttpExtensions.GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
tasks[1] = HttpExtensions.GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
//fails when add 3 or more task
tasks[2] = HttpExtensions.GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
//tasks[3] = HttpExtensions.GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
Task.WaitAll(tasks);
var result4 = ((Task<Stream>)tasks[2]).Result;
}
}
public static class HttpExtensions
{
public static Stopwatch sw;
public static long http_ticks = 0;
public static Task<HttpWebResponse> GetResponseAsync(this HttpWebRequest request)
{
var taskComplete = new TaskCompletionSource<HttpWebResponse>();
request.BeginGetResponse(asyncResponse =>
{
try
{
HttpWebRequest responseRequest = (HttpWebRequest)asyncResponse.AsyncState;
HttpWebResponse someResponse = (HttpWebResponse)responseRequest.EndGetResponse(asyncResponse);
taskComplete.TrySetResult(someResponse);
}
catch (WebException webExc)
{
HttpWebResponse failedResponse = (HttpWebResponse)webExc.Response;
taskComplete.TrySetResult(failedResponse);
}
}, request);
return taskComplete.Task;
}
public static async Task<Stream> GetMyData(string urlToCall)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlToCall);
request.Method = HttpMethod.Get;
HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
//using (var sr = new StreamReader(response.GetResponseStream()))
//{
return response.GetResponseStream();
//}
}
}
public static class HttpMethod
{
public static string Head { get { return "HEAD"; } }
public static string Post { get { return "POST"; } }
public static string Put { get { return "PUT"; } }
public static string Get { get { return "GET"; } }
public static string Delete { get { return "DELETE"; } }
public static string Trace { get { return "TRACE"; } }
public static string Options { get { return "OPTIONS"; } }
public static string Connect { get { return "CONNECT"; } }
public static string Patch { get { return "PATCH"; } }
}
}
There a number of concerns.
First, as I mentioned in the comments above, by not returning a Task you are more or less hanging your application since it can't tell when the Task is completed.
However, once you change the Run() method to return a task, you need to invoke it via a Task.Run call in your Main method.
Second, you are over-complicating your code by using WebClient. Switch to HttpClient and take advantage of its natural async/await API.
Third, you aren't actually awaiting anything in your Run() method so changing it to a task does nothing since you aren't awaiting a result which will cause it to run synchronously (no pun intended). Update your method to await a result.
Finally, WaitAll blocks the thread, which may not be what you want. You can use WhenAll instead and await that call, allowing your application to release the thread while your tasks run.
Below is a complete, working example of my recommended modifications, simplified to show a working program. The Main method recommendation is taken from https://social.msdn.microsoft.com/Forums/vstudio/en-US/fe9acdfc-66cd-4b43-9460-a8053ca51885/using-new-asyncawait-in-console-app?forum=netfxbcl
class Program
{
static Task[] tasks = new Task[3];
static HttpClient _client = new HttpClient();
static void Main(string[] args)
{
Console.WriteLine("Main start");
Task t = Run();
t.ContinueWith((str) =>
{
Console.WriteLine(str.Status.ToString());
Console.WriteLine("Main end");
});
t.Wait();
}
public static async Task Run()
{
tasks[0] = GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
tasks[1] = GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
tasks[2] = GetMyData("http://www.w3.org/TR/PNG/iso_8859-1.txt");
await Task.WhenAll(tasks);
var result4 = (await (Task<Stream>)tasks[2]);
}
public static async Task<Stream> GetMyData(string urlToCall)
{
return await _client.GetStreamAsync(urlToCall);
}
}
I think the issue is more of understanding Task and async await; and I may be wrong so apologies up front.
Task is a managed thread that goes into a thread pool. Task has a Task.Result of Type T.
You can create a Task and then Start it and then Wait it. (Never a good idea to start and then immediately wait a task but for understanding...)
var task = new Task(() => DoWork());
task.Start();
task.Wait();
The task will perform the DoWork() method in a new thread.
The calling thread will BLOCK at task.Wait();
You can also give a Task a ContinueWith Action that will perform the remaining work on the calling thread.
var task = new Task(() => DoWorkOnNewThread());
task.ContinueWith(() => MainThreadWork());
task.Start(); //Notice no more task.Wait();
So, if you're following that little bit then you can sort of use async await correctly.
The async keyword tells the compiler to wrap all remaing code AFTER reaching the await keyword WHERE A GetAwaiter() is returned. This is important because until you actually create a task (preferably started also) and return it then you have no GetAwaiter();
private Task DoWorkAsync()
{
var task = new Task(() => DoWork());
task.Start();
return task;
}
private async void Method()
{
//Main thread code...
await DoWorkAsync(); //Returns to whoever called Method()
//More main thread code to be QUEUED to run AFTER DoWorkAsync is complete.
//This portion of code, when compiled, is essentially wrapped in the ContinueWith(...
}
So if you're still following along then here's the kicker. You're on the same thread UNTIL you return a GetAwaiter() which is only found in a Task. If the Task has never started then you'll await that Task forever technically. So here's some comments showing the thread transitions.
private Task DoWorkAsync()
{
Debug.WriteLine("Still on main thread")
var task = new Task(() =>
{
Debug.WriteLine("On background thread");
});
task.Start(); //On main thread.
return task; //On main thread.
}
private async void Method()
{
Debug.WriteLine("On main thread");
await DoWorkAsync(); //returns to caller after DoWorkAsync returns Task
Debug.WriteLine("Back on main thread"); //Works here after the task DoWorkAsync returned is complete
}
An easier way to return the task running is to return Task.Run(() => DoWork()); If you look at the return value of Run it is Task and that task has already been started.
Forgive me if this isn't what you wanted but I felt like there is more of a confusion about using async await correctly than there is confusion about your code. I may be wrong but I felt that if you could understand more about the Task itself and how async await works you would see your issue. If this isn't what you're looking for I'll delete the answer.

Entity object inside Async and Await process

I'm trying to use Async and Await for upload process. I created a small code to see if it works.
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
TestAsync().Wait();
}
}
public static async Task TestAsync()
{
await Task.Run(() => {
Thread.Sleep(1000);
var context = new CommonEntities();
context.AddToDummies(new Dummy { TimeStamp = DateTime.Now, Caption = "Async" });
context.SaveChanges();
});
}
}
But for some reason, it never gets to Console.WriteLine. If I replaced var context = new EntityObject(); with var stringBuilder = new StringBuilder(); then it worked.
The idea is that I will create a method which has many complex procedures of saving and updating database as well as calling a webservice and store the result to database etc. Let say that method is called MethodA.
public static async void test()
{
await Task.Run(() => MethodA());
}
But before going further, I am stuck in this simple test. Any idea why that is?
You shouldn't be using async void anywhere other than an event handler.
async void doesn't allow the caller to wait (asynchronously or otherwise) for the operation to complete, it just moves on. In your case it reaches the end of Main and the application ends before you get a chance to reach the Console.WriteLine.
You need to change TestAsync to return a Task and wait for it in Main:
static void Main()
{
TestAsync().Wait();
}
public static async Task TestAsync()
{
await Task.Run(() =>
{
var objectContext = new CommonEntities();
Console.WriteLine("Processed");
});
}

Categories

Resources