Simplier way to trigger HttpClient (maybe without Task)? - c#

Im working on app that will consume my own REST endpoints (i have my onw WebApi project). Now i try to build app that will work on this endpoint.
Based on this MSDN tutorial i make something like this:
For testing, i make Console Core app. Main class look like this:
class Program
{
public static HttpDataService http = new HttpDataService("authorization token here");
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
RunAsync().GetAwaiter().GetResult();
}
static async Task RunAsync()
{
var data = await http.Get("Default");
}
}
My main Http class looks like this:
public class HttpDataService
{
public HttpDataService(string token)
{
this.HttpClient = new HttpClient();
this.HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
}
private HttpClient HttpClient { get; set; }
public async Task<object> Get(string controller)
{
object data;
HttpResponseMessage response = await this.HttpClient.GetAsync(UrlService.BuildEndpoint(controller));
if (response.IsSuccessStatusCode)
{
data = await response.Content.ReadAsAsync<object>();
return data;
}
else
{
throw new Exception(); //todo
}
}
}
I didnt like additional step, that i need to do method for run task (RunAsync.GetAwaiter... in Main method).
Is there simplier way to consuming my own endpoints? Maybe some other lib, that dont need to have additional method (in this way, static Async Task Run)? Is there way to just trigger method like:
http.Get("Projects");
Without RunAsync() method that i write before?
PS. that console app works ok (i get values from Default controller from my WebApi proj)
EDIT
That way looks more user-friendly:
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
Task get = http.Get("default");
RunAsync(get).GetAwaiter().GetResult();
}
static async Task RunAsync(Task endpoint)
{
await endpoint;
}
but how to get that from endpoint?

There are 2 issues with your code. The first one is that your RunAsync method returns Task while your method HttpDataService.Get return Task<object>. To get your result from the endpoint, RunAsync should return Task<object>. When you await this task, you will get an object with your result.
For the .GetAwaiter().GetResult(), there are 2 options. Firstly, you could create a static async Task MainAsync where you run all your code and call this method from the non-sync Main-method by invoking MainAsync().GetAwaiter().GetResult(). Before C# 7.1, this was the way to go.
static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
}
static async Task MainAsync(string[] args)
{
// Run your async code here
}
If you use C# 7.1, you can make your Main-method async (static async Task Main(string[] args)) and from there you can call your async code directly.
static async Task Main(string[] args)
{
// Run your async code here
}

Your can use an helper class
public static class AsyncHelper
{
private static readonly TaskFactory _taskFactory = new
TaskFactory(CancellationToken.None,
TaskCreationOptions.None,
TaskContinuationOptions.None,
TaskScheduler.Default);
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
=> _taskFactory
.StartNew(func)
.Unwrap()
.GetAwaiter()
.GetResult();
public static void RunSync(Func<Task> func)
=> _taskFactory
.StartNew(func)
.Unwrap()
.GetAwaiter()
.GetResult();
}
Allowing you to do that :
static async Task RunAsync(Task endpoint) {
AsyncHelper.RunSync(() => endpoint());
}
PS. have a look here Ms AsyncHelper and here C# Async Tips & Tricks

You should make Main async.
note : works only with modern c#
static async Task Main(string[] args)
{
var result = await http.Get("default");
}

Related

Simple.OData.Client not returning results, no error [duplicate]

public class test
{
public async Task Go()
{
await PrintAnswerToLife();
Console.WriteLine("done");
}
public async Task PrintAnswerToLife()
{
int answer = await GetAnswerToLife();
Console.WriteLine(answer);
}
public async Task<int> GetAnswerToLife()
{
await Task.Delay(5000);
int answer = 21 * 2;
return answer;
}
}
if I want to call Go in main() method, how can I do that?
I am trying out c# new features, I know i can hook the async method to a event and by triggering that event, async method can be called.
But what if I want to call it directly in main method? How can i do that?
I did something like
class Program
{
static void Main(string[] args)
{
test t = new test();
t.Go().GetAwaiter().OnCompleted(() =>
{
Console.WriteLine("finished");
});
Console.ReadKey();
}
}
But seems it's a dead lock and nothing is printed on the screen.
Your Main method can be simplified. For C# 7.1 and newer:
static async Task Main(string[] args)
{
test t = new test();
await t.Go();
Console.WriteLine("finished");
Console.ReadKey();
}
For earlier versions of C#:
static void Main(string[] args)
{
test t = new test();
t.Go().Wait();
Console.WriteLine("finished");
Console.ReadKey();
}
This is part of the beauty of the async keyword (and related functionality): the use and confusing nature of callbacks is greatly reduced or eliminated.
Instead of Wait, you're better off using
new test().Go().GetAwaiter().GetResult()
since this will avoid exceptions being wrapped into AggregateExceptions, so you can just surround your Go() method with a try catch(Exception ex) block as usual.
Since the release of C# v7.1 async main methods have become available to use which avoids the need for the workarounds in the answers already posted. The following signatures have been added:
public static Task Main();
public static Task<int> Main();
public static Task Main(string[] args);
public static Task<int> Main(string[] args);
This allows you to write your code like this:
static async Task Main(string[] args)
{
await DoSomethingAsync();
}
static async Task DoSomethingAsync()
{
//...
}
class Program
{
static void Main(string[] args)
{
test t = new test();
Task.Run(async () => await t.Go());
}
}
As long as you are accessing the result object from the returned task, there is no need to use GetAwaiter at all (Only in case you are accessing the result).
static async Task<String> sayHelloAsync(){
await Task.Delay(1000);
return "hello world";
}
static void main(string[] args){
var data = sayHelloAsync();
//implicitly waits for the result and makes synchronous call.
//no need for Console.ReadKey()
Console.Write(data.Result);
//synchronous call .. same as previous one
Console.Write(sayHelloAsync().GetAwaiter().GetResult());
}
if you want to wait for a task to be done and do some further processing:
sayHelloAsyn().GetAwaiter().OnCompleted(() => {
Console.Write("done" );
});
Console.ReadLine();
If you are interested in getting the results from sayHelloAsync and do further processing on it:
sayHelloAsync().ContinueWith(prev => {
//prev.Result should have "hello world"
Console.Write("done do further processing here .. here is the result from sayHelloAsync" + prev.Result);
});
Console.ReadLine();
One last simple way to wait for function:
static void main(string[] args){
sayHelloAsync().Wait();
Console.Read();
}
static async Task sayHelloAsync(){
await Task.Delay(1000);
Console.Write( "hello world");
}
public static void Main(string[] args)
{
var t = new test();
Task.Run(async () => { await t.Go();}).Wait();
}
Use .Wait()
static void Main(string[] args){
SomeTaskManager someTaskManager = new SomeTaskManager();
Task<List<String>> task = Task.Run(() => marginaleNotesGenerationTask.Execute());
task.Wait();
List<String> r = task.Result;
}
public class SomeTaskManager
{
public async Task<List<String>> Execute() {
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:4000/");
client.DefaultRequestHeaders.Accept.Clear();
HttpContent httpContent = new StringContent(jsonEnvellope, Encoding.UTF8, "application/json");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage httpResponse = await client.PostAsync("", httpContent);
if (httpResponse.Content != null)
{
string responseContent = await httpResponse.Content.ReadAsStringAsync();
dynamic answer = JsonConvert.DeserializeObject(responseContent);
summaries = answer[0].ToObject<List<String>>();
}
}
}
try "Result" property
class Program
{
static void Main(string[] args)
{
test t = new test();
t.Go().Result;
Console.ReadKey();
}
}
C# 9 Top-level statements simplified things even more, now you don't even have to do anything extra to call async methods from your Main, you can just do this:
using System;
using System.Threading.Tasks;
await Task.Delay(1000);
Console.WriteLine("Hello World!");
For more information see What's new in C# 9.0, Top-level statements:
The top-level statements may contain async expressions. In that case, the synthesized entry point returns a Task, or Task<int>.

Async method sending response back to Main

I have implemented a soap client using a Async method. I want this method to return a string value that I get from the API server to my main Thread or to another method (whichever method is calling). How do I do this:
MAIN THREAD
static void Main(string[] args)
{
TEXT().GetAwaiter().OnCompleted(() => { Console.WriteLine("finished"); });
Console.ReadKey();
// if I do it like this
// var test = TEXT().GetAwaiter().OnCompleted(() => { Console.WriteLine("finished"); });
// it gives me error: Cannot assign void to an implicitly-typed local variable
}
ASYNC METHOD
public static async Task<string> TEXT()
{
Uri uri = new Uri("http://myaddress");
HttpClient hc = new HttpClient();
hc.DefaultRequestHeaders.Add("SOAPAction", "Some Action");
var xmlStr = "SoapContent"; //not displayed here for simplicity
var content = new StringContent(xmlStr, Encoding.UTF8, "text/xml");
using (HttpResponseMessage response = await hc.PostAsync(uri, content))
{
var soapResponse = await response.Content.ReadAsStringAsync();
string value = await response.Content.ReadAsStringAsync();
return value; //how do I get this back to the main thread or any other method
}
}
In a pre-C# 7.0 console application it can be achieved as simple as this:
public static void Main()
{
string result = TEXT().Result;
Console.WriteLine(result);
}
In this case TEXT can be considered a usual method, which returns Task<string>, so its result is available in Result property. You don't need to mess with awaiter, results etc.
At the same time, you cannot do this in most types of applications (WinForms, WPF, ASP.NET etc.) and in this case you will have to use async/await across all your application:
public async Task SomeMethod()
{
string result = await TEXT();
// ... do something with result
}
If you plan to do a lot of async in a console application, I recommend using this sort of MainAsync pattern:
static public void Main(string[] args) //Entry point
{
MainAsync(args).GetAwaiter().GetResult();
}
static public Task MainAsync(string[] args) //Async entry point
{
await TEXT();
Console.WriteLine("finished");
}
If you upgrade to C# 7.1 or later, you can then remove the Main method and use async main.
Or if you ever migrate this code to an ASP.NET or WinForms application, you can ignore Main and migrate the code in MainAsync (otherwise you will run afoul of the synchronization model and get deadlocked).
In C# 7.0+, you can use async Task Main
static async Task Main(string[] args)
{
var result = TEXT().ConfigureAwait(false)
Console.ReadKey();
}
for older versions of C#
public static void Main(string[] args)
{
try
{
TEST().GetAwaiter().GetResult();
}
catch (Exception ex)
{
WriteLine($"There was an exception: {ex.ToString()}");
}
}

async Main wouldn't compile [duplicate]

I copied below code from this link.But when I am compiling this code I am getting an entry point cannot be marked with the 'async' modifier. How can I make this code compilable?
class Program
{
static async void Main(string[] args)
{
Task<string> getWebPageTask = GetWebPageAsync("http://msdn.microsoft.com");
Debug.WriteLine("In startButton_Click before await");
string webText = await getWebPageTask;
Debug.WriteLine("Characters received: " + webText.Length.ToString());
}
private static async Task<string> GetWebPageAsync(string url)
{
// Start an async task.
Task<string> getStringTask = (new HttpClient()).GetStringAsync(url);
// Await the task. This is what happens:
// 1. Execution immediately returns to the calling method, returning a
// different task from the task created in the previous statement.
// Execution in this method is suspended.
// 2. When the task created in the previous statement completes, the
// result from the GetStringAsync method is produced by the Await
// statement, and execution continues within this method.
Debug.WriteLine("In GetWebPageAsync before await");
string webText = await getStringTask;
Debug.WriteLine("In GetWebPageAsync after await");
return webText;
}
// Output:
// In GetWebPageAsync before await
// In startButton_Click before await
// In GetWebPageAsync after await
// Characters received: 44306
}
The error message is exactly right: the Main() method cannot be async, because when Main() returns, the application usually ends.
If you want to make a console application that uses async, a simple solution is to create an async version of Main() and synchronously Wait() on that from the real Main():
static void Main()
{
MainAsync().Wait();
}
static async Task MainAsync()
{
// your async code here
}
This is one of the rare cases where mixing await and Wait() is a good idea, you shouldn't usually do that.
Update: Async Main is supported in C# 7.1.
Starting from C# 7.1 there are 4 new signatures for Main method which allow to make it async(Source, Source 2, Source 3):
public static Task Main();
public static Task<int> Main();
public static Task Main(string[] args);
public static Task<int> Main(string[] args);
You can mark your Main method with async keyword and use await inside Main:
static async Task Main(string[] args)
{
Task<string> getWebPageTask = GetWebPageAsync("http://msdn.microsoft.com");
Debug.WriteLine("In startButton_Click before await");
string webText = await getWebPageTask;
Debug.WriteLine("Characters received: " + webText.Length.ToString());
}
C# 7.1 is available in Visual Studio 2017 15.3.
I'm using C# 8 and its working fine.
static async Task Main(string[] args)
{
var response = await SomeAsyncFunc();
Console.WriteLine("Async response", response);
}
OR without "await" keyword.
static void Main(string[] args)
{
var response = SomeAsyncFunc().GetAwaiter().GetResult();
Console.WriteLine("Async response", response);
}
The difference between the code in the link's example and yours, is that you're trying to mark the Main() method with an async modifier - this is not allowed, and the error says that exactly - the Main() method is the "entry point" to the application (it's the method that is executed when your application starts), and it's not allowed to be async.
Wrap your async code in MainAsync() - which is an async function
then call MainAsync().GetAwaiter().GetResult();

Awaiting SQL client async in the Main Method [duplicate]

I am new to asynchronous programming with the async modifier. I am trying to figure out how to make sure that my Main method of a console application actually runs asynchronously.
class Program
{
static void Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = bs.GetList();
}
}
public class Bootstrapper {
public async Task<List<TvChannel>> GetList()
{
GetPrograms pro = new GetPrograms();
return await pro.DownloadTvChannels();
}
}
I know this is not running asynchronously from "the top." Since it is not possible to specify the async modifier on the Main method, how can I run code within main asynchronously?
As you discovered, in VS11 the compiler will disallow an async Main method. This was allowed (but never recommended) in VS2010 with the Async CTP.
Update, 2017-11-30: As of Visual Studio 2017 Update 3 (15.3), the language now supports an async Main - as long as it returns Task or Task<T>. So you can now do this:
class Program
{
static async Task Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
The semantics appear to be the same as the GetAwaiter().GetResult() style of blocking the main thread. However, there's no language spec for C# 7.1 yet, so this is only an assumption.
I have recent blog posts about async/await and asynchronous console programs in particular. Here's some background info from the intro post:
If "await" sees that the awaitable has not completed, then it acts asynchronously. It tells the awaitable to run the remainder of the method when it completes, and then returns from the async method. Await will also capture the current context when it passes the remainder of the method to the awaitable.
Later on, when the awaitable completes, it will execute the remainder of the async method (within the captured context).
Here's why this is a problem in Console programs with an async Main:
Remember from our intro post that an async method will return to its caller before it is complete. This works perfectly in UI applications (the method just returns to the UI event loop) and ASP.NET applications (the method returns off the thread but keeps the request alive). It doesn't work out so well for Console programs: Main returns to the OS - so your program exits.
One solution is to provide your own context - a "main loop" for your console program that is async-compatible.
If you have a machine with the Async CTP, you can use GeneralThreadAffineContext from My Documents\Microsoft Visual Studio Async CTP\Samples(C# Testing) Unit Testing\AsyncTestUtilities. Alternatively, you can use AsyncContext from my Nito.AsyncEx NuGet package.
Here's an example using AsyncContext; GeneralThreadAffineContext has almost identical usage:
using Nito.AsyncEx;
class Program
{
static void Main(string[] args)
{
AsyncContext.Run(() => MainAsync(args));
}
static async void MainAsync(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
Alternatively, you can just block the main Console thread until your asynchronous work has completed:
class Program
{
static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
}
static async Task MainAsync(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
Note the use of GetAwaiter().GetResult(); this avoids the AggregateException wrapping that happens if you use Wait() or Result.
You can solve this with this simple construct:
class Program
{
static void Main(string[] args)
{
Task.Run(async () =>
{
// Do any async anything you need here without worry
}).GetAwaiter().GetResult();
}
}
That will put everything you do out on the ThreadPool where you'd want it (so other Tasks you start/await don't attempt to rejoin a Thread they shouldn't), and wait until everything's done before closing the Console app. No need for special loops or outside libs.
Edit: Incorporate Andrew's solution for uncaught Exceptions.
You can do this without needing external libraries also by doing the following:
class Program
{
static void Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var getListTask = bs.GetList(); // returns the Task<List<TvChannel>>
Task.WaitAll(getListTask); // block while the task completes
var list = getListTask.Result;
}
}
In C# 7.1 you will be able to do a proper async Main. The appropriate signatures for Main method has been extended to:
public static Task Main();
public static Task<int> Main();
public static Task Main(string[] args);
public static Task<int> Main(string[] args);
For e.g. you could be doing:
static async Task Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
At compile time, the async entry point method will be translated to call GetAwaitor().GetResult().
Details: https://blogs.msdn.microsoft.com/mazhou/2017/05/30/c-7-series-part-2-async-main
EDIT:
To enable C# 7.1 language features, you need to right-click on the project and click "Properties" then go to the "Build" tab. There, click the advanced button at the bottom:
From the language version drop-down menu, select "7.1" (or any higher value):
The default is "latest major version" which would evaluate (at the time of this writing) to C# 7.0, which does not support async main in console apps.
I'll add an important feature that all of the other answers have overlooked: cancellation.
One of the big things in TPL is cancellation support, and console apps have a method of cancellation built in (CTRL+C). It's very simple to bind them together. This is how I structure all of my async console apps:
static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
System.Console.CancelKeyPress += (s, e) =>
{
e.Cancel = true;
cts.Cancel();
};
MainAsync(args, cts.Token).GetAwaiter.GetResult();
}
static async Task MainAsync(string[] args, CancellationToken token)
{
...
}
C# 7.1 (using vs 2017 update 3) introduces async main
You can write:
static async Task Main(string[] args)
{
await ...
}
For more details C# 7 Series, Part 2: Async Main
Update:
You may get a compilation error:
Program does not contain a static 'Main' method suitable for an entry point
This error is due to that vs2017.3 is configured by default as c#7.0 not c#7.1.
You should explicitly modify the setting of your project to set c#7.1 features.
You can set c#7.1 by two methods:
Method 1: Using the project settings window:
Open the settings of your project
Select the Build tab
Click the Advanced button
Select the version you want
As shown in the following figure:
Method2: Modify PropertyGroup of .csproj manually
Add this property:
<LangVersion>7.1</LangVersion>
example:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<LangVersion>7.1</LangVersion>
</PropertyGroup>
If you're using C# 7.1 or later, go with the nawfal's answer and just change the return type of your Main method to Task or Task<int>. If you are not:
Have an async Task MainAsync like Johan said.
Call its .GetAwaiter().GetResult() to catch the underlying exception like do0g said.
Support cancellation like Cory said.
A second CTRL+C should terminate the process immediately. (Thanks binki!)
Handle OperationCancelledException - return an appropriate error code.
The final code looks like:
private static int Main(string[] args)
{
var cts = new CancellationTokenSource();
Console.CancelKeyPress += (s, e) =>
{
e.Cancel = !cts.IsCancellationRequested;
cts.Cancel();
};
try
{
return MainAsync(args, cts.Token).GetAwaiter().GetResult();
}
catch (OperationCanceledException)
{
return 1223; // Cancelled.
}
}
private static async Task<int> MainAsync(string[] args, CancellationToken cancellationToken)
{
// Your code...
return await Task.FromResult(0); // Success.
}
Haven't needed this much yet, but when I've used console application for Quick tests and required async I've just solved it like this:
class Program
{
static void Main(string[] args)
{
MainAsync(args).Wait();
}
static async Task MainAsync(string[] args)
{
// Code here
}
}
For asynchronously calling task from Main, use
Task.Run() for .NET 4.5
Task.Factory.StartNew() for .NET 4.0 (May require Microsoft.Bcl.Async library for async and await keywords)
Details:
http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx
In Main try changing the call to GetList to:
Task.Run(() => bs.GetList());
When the C# 5 CTP was introduced, you certainly could mark Main with async... although it was generally not a good idea to do so. I believe this was changed by the release of VS 2013 to become an error.
Unless you've started any other foreground threads, your program will exit when Main completes, even if it's started some background work.
What are you really trying to do? Note that your GetList() method really doesn't need to be async at the moment - it's adding an extra layer for no real reason. It's logically equivalent to (but more complicated than):
public Task<List<TvChannel>> GetList()
{
return new GetPrograms().DownloadTvChannels();
}
Newest version of C# - C# 7.1 allows to create async console app. To enable C# 7.1 in project, you have to upgrade your VS to at least 15.3, and change C# version to C# 7.1 or C# latest minor version. To do this, go to Project properties -> Build -> Advanced -> Language version.
After this, following code will work:
internal class Program
{
public static async Task Main(string[] args)
{
(...)
}
As of C# 7.1 the following signatures are valid for the Main method.
public static void Main() { }
public static int Main() { }
public static void Main(string[] args) { }
public static int Main(string[] args) { }
public static async Task Main() { }
public static async Task<int> Main() { }
public static async Task Main(string[] args) { }
public static async Task<int> Main(string[] args) { }
So, now you can do async/await
static async Task Main(string[] args)
{
Console.WriteLine("Hello Asyn Main method!");
await Task.Delay(200);
}
On MSDN, the documentation for Task.Run Method (Action) provides this example which shows how to run a method asynchronously from main:
using System;
using System.Threading;
using System.Threading.Tasks;
public class Example
{
public static void Main()
{
ShowThreadInfo("Application");
var t = Task.Run(() => ShowThreadInfo("Task") );
t.Wait();
}
static void ShowThreadInfo(String s)
{
Console.WriteLine("{0} Thread ID: {1}",
s, Thread.CurrentThread.ManagedThreadId);
}
}
// The example displays the following output:
// Application thread ID: 1
// Task thread ID: 3
Note this statement that follows the example:
The examples show that the asynchronous task executes on a different
thread than the main application thread.
So, if instead you want the task to run on the main application thread, see the answer by #StephenCleary.
And regarding the thread on which the task runs, also note Stephen's comment on his answer:
You can use a simple Wait or Result, and there's nothing wrong
with that. But be aware that there are two important differences: 1)
all async continuations run on the thread pool rather than the main
thread, and 2) any exceptions are wrapped in an AggregateException.
(See Exception Handling (Task Parallel Library) for how to incorporate exception handling to deal with an AggregateException.)
Finally, on MSDN from the documentation for Task.Delay Method (TimeSpan), this example shows how to run an asynchronous task that returns a value:
using System;
using System.Threading.Tasks;
public class Example
{
public static void Main()
{
var t = Task.Run(async delegate
{
await Task.Delay(TimeSpan.FromSeconds(1.5));
return 42;
});
t.Wait();
Console.WriteLine("Task t Status: {0}, Result: {1}",
t.Status, t.Result);
}
}
// The example displays the following output:
// Task t Status: RanToCompletion, Result: 42
Note that instead of passing a delegate to Task.Run, you can instead pass a lambda function like this:
var t = Task.Run(async () =>
{
await Task.Delay(TimeSpan.FromSeconds(1.5));
return 42;
});
In my case I had a list of jobs that I wanted to run in async from my main method, have been using this in production for quite sometime and works fine.
static void Main(string[] args)
{
Task.Run(async () => { await Task.WhenAll(jobslist.Select(nl => RunMulti(nl))); }).GetAwaiter().GetResult();
}
private static async Task RunMulti(List<string> joblist)
{
await ...
}
To avoid freezing when you call a function somewhere down the call stack that tries to re-join the current thread (which is stuck in a Wait), you need to do the following:
class Program
{
static void Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
List<TvChannel> list = Task.Run((Func<Task<List<TvChannel>>>)bs.GetList).Result;
}
}
(the cast is only required to resolve ambiguity)
class Program
{
public static EventHandler AsyncHandler;
static void Main(string[] args)
{
AsyncHandler+= async (sender, eventArgs) => { await AsyncMain(); };
AsyncHandler?.Invoke(null, null);
}
private async Task AsyncMain()
{
//Your Async Code
}
}
This is hypothetical but I am thinking:
static void Main(string[] args)
{
var context = new Thread(() => /*do stuff*/);
context.Start();
context.Join();
}
Not sure if this is what you're looking for, but I wanted to await a method on load. I ended up using the Main_Shown handler and making it async:
private async void Main_Shown(object sender, EventArgs e)
{
await myAsyncMethod();
}
The following code can be used to make a main async. I've tweak it to use long running tasks (learn more here: https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcreationoptions?view=net-7.0)
It's also implementing the cancellation token from the above response.
private static int Main(string[] args)
{
var cts = new CancellationTokenSource();
Console.CancelKeyPress += (s, e) =>
{
e.Cancel = !cts.IsCancellationRequested;
cts.Cancel();
Console.WriteLine("CancellationRequested");
};
try
{
var task = new Task<int>(
() => MainAsync(args, cts.Token).GetAwaiter().GetResult(),
cts.Token,
TaskCreationOptions.LongRunning //https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcreationoptions?view=net-7.0
);
task.Start();
var exitCode = task.GetAwaiter().GetResult();
/*Or this.*/
//var exitCode = MainAsync(args, cts.Token).GetAwaiter().GetResult();
return exitCode;// MainAsync(args, cts.Token).GetAwaiter().GetResult();
}
catch (OperationCanceledException ex)
{
Console.WriteLine(ex);
return 1223; // Cancelled.
}
catch(Exception ex)
{
Console.WriteLine(ex);
return -1;
}
}
private static async Task<int> MainAsync(string[] args, CancellationToken cancellationToken)
{
await Something()
return;
}
In the following example I wrote. You can play with maxDegreeOfParallelism & numberOfIteration to understand / see how the task are handle. Good statring point for learning TPL!
private static async Task<int> MainAsync(string[] args, CancellationToken cancellationToken)
{
var infos = new ConcurrentBag<Info>();
var mySuperUselessService = new BigWorkload();
int numberOfSecond = 1;
int numberOfIteration = 25; //Experiment with this
int maxDegreeOfParallelism = 4; //Experiment with this
var simulateWorkTime = TimeSpan.FromSeconds(numberOfSecond);
var informations = Enumerable.Range(1, numberOfIteration)
.Select(x => new Info() { Index = x });
var count = informations.Count();
var chunkNeeded = Math.Round(count / Convert.ToDecimal(maxDegreeOfParallelism), MidpointRounding.ToPositiveInfinity);
var splashInfo = #$"
Press CTRL + C to cancel.
Processing {count} items, maxDegreeOfParallelism set to {maxDegreeOfParallelism}.
But it will be bound by the core on the machine {Environment.ProcessorCount}.
This operation should take ~{chunkNeeded * (numberOfSecond + 0.01m)}s
And will be starting test in 2s
";
Console.WriteLine(splashInfo);
await Task.Delay(TimeSpan.FromSeconds(2));
var parralelOptions = new ParallelOptions() { MaxDegreeOfParallelism = maxDegreeOfParallelism, CancellationToken = cancellationToken};
var stopwatch = new Stopwatch();
stopwatch.Start();
var forLoopTask = Parallel.ForEachAsync(informations, parralelOptions, async (info, token) =>
{
await mySuperUselessService.Simulate(simulateWorkTime, info);
Console.WriteLine(info);
infos.Add(info);
});
await forLoopTask;
stopwatch.Stop();
foreach (var grouped in infos.GroupBy(x => x.ManagedThreadId))
{
Console.WriteLine($"ThreadId: {grouped.Key}");
foreach (var item in grouped)
{
Console.WriteLine($"\t Index: {item.Index} {item.TaskCurrentId}");
}
}
Console.WriteLine($"NumberOfThread: {infos.GroupBy(x => x.ManagedThreadId).Count()}");
Console.WriteLine($"Elasped: {stopwatch.ElapsedMilliseconds / 1000d}s");
Console.WriteLine(splashInfo);
return 0;
}

c# Can a "task method" also be an "async" method?

I'm trying to get the hand of the new async CTP stuff and I'm probably confusing myself here..
I can have this "task method", with no problem:
public static Task<String> LongTaskAAsync() {
return Task.Run(() => {
return("AAA");
});
}
But what if I need the task to execute another task, can I mark it as "async" and use "await"? I tried this:
public async static Task<String> LongTaskAAsync() {
await Task.Delay(2000);
return Task.Run(() => {
return("AAA");
});
}
But then mysteriously get this compiler error: Since this is an async method, the return expression must be of type 'string' rather than Task<string>
What am I missing here?
You may want to read my async/await intro post.
Return values from async methods are wrapped in a Task<TResult>. Likewise, await unwraps those return values:
public static async Task<String> LongTaskAAsync() {
await Task.Delay(2000);
return await Task.Run(() => {
return("AAA");
});
}
The reasoning behind this is described in my Async "Why Do the Keywords Work That Way" Unofficial FAQ.
P.S. You can also use Task.FromResult for simple tests like this.
Edit: If you want to create and return the Task object itself, then the method should not be async. One somewhat common pattern is to have a public non-async method that calls the async portion only if necessary.
For example, some kind of asynchronous cache - if the object is in the cache, then return it immediately; otherwise, asynchronously create it, add it to the cache, and return it (this is example code - not thread-safe):
public static Task<MyClass> GetAsync(int key)
{
if (cache.Contains(key))
return Task.FromResult(cache[key]);
return CreateAndAddAsync(key);
}
private static async Task<MyClass> CreateAndAddAsync(int key)
{
var result = await CreateAsync(key);
cache.Add(key, result);
return result;
}
Can a “task method” also be an “async” method?
Yes it can be, by simply changing the method signature to public async static Task<Task<String>> LongTaskAAsync() since that is, what it will return.
If you use the async keyword, the runtime will wrap the type you return into a task, to enable asynchronousness. Say if you return a string, the runtime will wrap that into a Task<string>. int will go Task<int> and Task<string> will go Task<Task<string>>. See this console app to clearify:
public class Program
{
public static void Main(string[] args)
{
// start the main procedure asynchron
Task.Run(() => DoIt()).Wait();
}
// for async support since the static main method can't be async
public static async void DoIt()
{
Program p = new Program();
// use the methods
string s = await p.GetString();
int i = await p.GetInt();
Task<string> tsk = await p.GetTaskOfString();
// just to prove the task works:
// C# 5
string resultFromReturnedTask = await tsk;
// C# 4
string resultFromReturnedTask2 = tsk.Result;
}
public async Task<string> GetString()
{
return "string";
}
public async Task<int> GetInt()
{
return 6;
}
public async Task<Task<string>> GetTaskOfString()
{
return Task.Run(() => "string");
}
}

Categories