Is async code that easy? - c#

I am working on a C# Hue application, I am creating the api calls myself for the learning experience. Since Hue consists of many network calls i wanted to also provide an async method for every sync method i create. I wrote some lines of code and thought to myself "This can't possibly be so easy", so now I'm here and wanted to ask if this is a good way to implement async functions? Also any other optimizations to my code are appreciated.
using System.IO;
using System.Net;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace SharpHue
{
public class HueUtilities
{
const string DISCOVERY_URI = "http://www.meethue.com/api/nupnp";
public struct DiscoveryElement
{
[JsonProperty("id")]
public string ID;
[JsonProperty("internalipaddress")]
public string Address;
}
public static DiscoveryElement[] DiscoverBridges()
{
string data = "[]";
var request = WebRequest.CreateHttp(DISCOVERY_URI);
try
{
var response = request.GetResponse();
using (var streamReader = new StreamReader(response.GetResponseStream()))
{
data = streamReader.ReadToEnd();
streamReader.Close();
response.Close();
}
return JsonConvert.DeserializeObject<DiscoveryElement[]>(data);
}
catch (Exception ex)
{
throw ex;
}
}
public static async Task<DiscoveryElement[]> DiscoverBridgesAsync()
{
return await Task.Run(() => DiscoverBridges());
}
}
}

Almost. But you should avoid Task.Run when there are true async alternatives. In your case that means replacing WebRequest class with HttpClient and call your code like this:
public static async Task<DiscoveryElement[]> DiscoverBridgesAsync()
{
using (var client = new HttpClient())
{
var result = await client.GetAsync(DISCOVERY_URI);
return await result.Content.ReadAsAsync<DiscoveryElement[]>();
}
}
As you can see there is no more use for the method that wrapped the synchronous call to an async call. It's now truly async/await compliant.
warning There might be some compile errors but should work.
More info: http://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client
And please, read this: http://www.ben-morris.com/why-you-shouldnt-create-asynchronous-wrappers-with-task-run/

No async code is notoriously difficult to write that's why they added the async keyword. the problem tends to be that people don't understand what async code is and why use it. This code
var result = await Task.FromResult(0);
Is similar to writing
Task.FromResult(0).ContinueWith((task)=>
{
var result = task.Result;
});
If the code is not Asynchronous using async keyword wont make it so. Your code is Asynchronous because of what Task.Run dose, not the async Keyword. Stuff like ReadStream and ReadstreamAsync actually might do two completely different things like with file access.
Task.Run will not act the same in something like Asp.Net and Wpf since asp dose not have a UI thread. Also tasks have nothing to do with threads they can run on a single thread and do in some cases.Akavache is grate example of how to do async programing on a single thread. You have to be carful using async if you don't understand what will be done in the background.

Related

Using MessageBox when part of an await has ConfigureAwait false

Reading Stephen Cleary take on not blocking on Async code I write something like this
public static async Task<JObject> GetJsonAsync(Uri uri)
{
using (var client = new HttpClient())
{
var jsonString = await client.GetStringAsync(uri).ConfigureAwait(false);
return JObject.Parse(jsonString);
}
}
public async void Button1_Click(...)
{
var json = await GetJsonAsync(...);
textBox1.Text=json;
}
so far so good, I understand that after the ConfigureAwait the method is going to continue running on a different context after GetStringAsync returns.
but what about if I want to use something like MessageBox (which is UI) like this
public static async Task<JObject> GetJsonAsync(Uri uri)
{
if(someValue<MAXVALUE)
{
using (var client = new HttpClient())
{
//var jsonString = await client.GetStringAsync(uri); //starts the REST request
var jsonString = await client.GetStringAsync(uri).ConfigureAwait(false);
return JObject.Parse(jsonString);
}
}
else
{
MessageBox.Show("The parameter someValue is too big!");
}
}
can I do this?
Even more complicated, how about this?
public static async Task<JObject> GetJsonAsync(Uri uri)
{
if(someValue<MAXVALUE)
{
try{
using (var client = new HttpClient())
{
//var jsonString = await client.GetStringAsync(uri); //starts the REST request
var jsonString = await client.GetStringAsync(uri).ConfigureAwait(false);
return JObject.Parse(jsonString);
}
}
catch(Exception ex)
{
MessageBox.Show("An Exception was raised!");
}
}
else
{
MessageBox.Show("The parameter someValue is too big!");
}
}
Can I do this?
Now, I am thinking perhaps all the message boxes should be called outside GetJsonAync as good design, but my question is can the above thing be done?
can I do this? [use a MessageBox]
Yes, but mainly because it has nothing to do with async/await or threading.
MessageBox.Show() is special, it is a static method and is documented as thread-safe.
You can show a MessageBox from any thread, any time.
So maybe it was the wrong example, but you do have MessageBox in the title.
public static async Task<JObject> GetJsonAsync(Uri uri)
{
try{
... // old context
... await client.GetStringAsync(uri).ConfigureAwait(false);
... // new context
}
catch
{
// this might bomb
someLabel.Text = "An Exception was raised!";
}
}
In this example, there could be code paths where the catch runs on the old and other paths where it runs on the new context.
Bottom line is: you don't know and should assume the worst case.
I would not use a Message Box, as it is very limited, and dated.
Also, Pop up's are annoying.
Use your own user control which enables user interaction the way you intend it.
In the context of Winforms / WPF / (and I guess UWP), only a single thread can manipulate the UI. Other threads can issue work to it via a queue of actions which eventually get invoked.
This architecture prevents other threads from constantly poking at the UI, which can make UX very janky (and thread unsafe).
The only way to communicate with it the UI work queue (in Winforms) is via the System.Windows.Form.Controls.BeginInvoke instance method, found on every form and control.
In your case:
public async void Button1_Click(...)
{
var json = await GetJsonAsync(...).ConfigureAwait(false);
BeginInvoke(UpdateTextBox, json);
}
private void UpdateTextBox(string value)
{
textBox1.Text=json;
}

Async requests with .NET core

I need a little help to find out my problem. I've used ASP.NET core and i'm fairly familiar with that, although .NET core C# seems to be "crashing" and exiting when trying to make my async request.
I have a method that returns the external IP of the system
private async Task<string> getExternalIP()
{
using (System.Net.Http.HttpClient HC = new System.Net.Http.HttpClient())
{
return await HC.GetStringAsync("https://api.ipify.org/");
}
}
This should work, but it exits when it reaches the HC.GetStringAsync. I've also tried putting a breakpoint on it but it doesn't actually run.
I'm trying to call the method by using
string Address = await getExternalIP();
Any help is thankful, hopefully i'm not just overlooking something.
Thanks!
Your proposed solution is not good at all.
It is synchronous
It can cause a deadlock
As an alternative, try this approach:
private async Task<string> GetExternalIP()
{
using (HttpClient client = new HttpClient())
return await client.GetStringAsync("https://api.ipify.org/");
}
Your calling method should be asynchronous too:
public async Task CallingMethod()
{
// ...
string address = await GetExternalIP();
// ...
}
The reason it was not working for you before was caused by the use of async void instead of async Task (guessed this by the comments).
async void is an asynchronous method that cannot be awaited. That means, you just call it and forget about it. You won't catch any exception, you won't get any return value.
async Task is an awaitable asynchronous method that does not return anything. It is the asynchronous counterpart for a void synchronous method. Furthermore, since it is awaitable, you'll also be able to catch any exception that may rise on the asynchronous code.

Async/await, run blocking the UI without obvious reason

I have been reasearching once again the async tasks. No mater how i set the Tasks, my application suffers from UI freeze all the time. I have the following code for downloading the string from a webpage:
internal string DownloadString(string URL)
{
var result = LoadCompanyContracts(URL);
return result.Result;
}
internal async Task<string> LoadCompanyContracts(string URL)
{
Task<string> task2 = Task<string>.Factory.StartNew(() =>
{
for (int i = 0; i <= 10000000; i++) Console.WriteLine(i);
WebClient wc = new WebClient();
string tmp = wc.DownloadString(new Uri(URL));
return tmp;
});
return task2.Result;
}
When i execute this task and during the for loop the UI of my application is freezing. Even though i believe that this code should not freeze the UI i am not able to find a solution. I have tried many different options and really want to use tasks instead of threads or events with webclient async.
Info: I am using .net 4.5 for my project. The difference in my code is that these functions are inside a class library(don't know if it matters).
Is it possible to run this code without blocking the user interface with async await by calling the DownloadString function from my code? If not what are the alternatives(any good nuget packages)?
The async keyword doesn't make something run asynchronously, it enables you to use await to await an already asynchronous operation. You need to use
DownloadStringTaskAsync to truly download in an asynchronous manner:
internal async Task<string> LoadCompanyContracts(string URL)
{
....
using(var wc = new WebClient())
{
string tmp = await wc.DownloadStringTaskAsync(new Uri(URL));
return tmp;
}
}
await by itself returns execution in the original execution context (ie the UI thread). This may or may not be desirable, which is why library code typically uses ConfigureAwait(false); and lets the final user of the library to decide how to await:
string tmp = await wc.DownloadStringTaskAsync(new Uri(URL))
.ConfigureAwait(false);
Finally, there's no point in awaiting if you are going to call .Result from the top-level function. There is no point in using await at all if you don't want to do use the method's result in your code. LoadCompanyContracts could be just:
internal Task<string> LoadCompanyContracts(string URL)
{
....
using(var wc = new WebClient())
{
return wc.DownloadStringTaskAsync(new Uri(URL))
.ConfigureAwait(false);
}
}
Oops
Typically, you don't need to use await at all if you just return the result of an asynchronous operation. The method could just return wc.DownloadStringTaskAsync(..); BUT that would cause the method to return and dispose the WebClient before download finishes. Avoiding the using block isn't a solution either, as it will let an expensive object like WebClient alive longer than necessary.
That's why HttpClient is preferable to WebClient: a single instance supports multiple concurrent calls, which means you can have just one instance eg as a field and reuse it, eg:
HttpClient _myClient =new HttpClient();
internal Task<string> LoadCompanyContractsAsync(string URL)
{
....
return _myClient.GetStringAsync(new Uri(URL))
.ConfigureAwait(false);
}
}
You could get rid of your DownloadString since it doesn't do anything on top of LoadCompanyContracts. If it does use the result of LoadCompanyContracts, it should be rewritten as:
internal async Task<string> DownloadString(string URL)
{
var result = await LoadCompanyContracts(URL);
//Do something with the result
return result;
}
EDIT
The original answer used DownloadStringAsync which is a legacy method that raises an event when download completes. The correct method is DownloadStringTaskAsync
EDIT 2
Since we are talking about a UI, the code can be made asynchronous all the way to the top event handler by using the async void syntax for the handler, eg async void Button1_Click, eg:
async void LoadCustomers_Click(...)
{
var contracts=await LoaCompanyContracts(_companyUrls);
txtContracts>Text=contracts;
}
In this case we want to return to the original thread, so we don't use ConfigureAwait(false);

Write C# async and "sync" code together in one method [duplicate]

This question already has answers here:
How to call asynchronous method from synchronous method in C#?
(17 answers)
Closed 6 years ago.
I have the below method:
public string RetrieveHolidayDatesFromSource() {
var result = this.RetrieveHolidayDatesFromSourceAsync();
/** Do stuff **/
var returnedResult = this.TransformResults(result.Result); /** Where result gets used **/
return returnedResult;
}
private async Task<string> RetrieveHolidayDatesFromSourceAsync() {
using (var httpClient = new HttpClient()) {
var json = await httpClient.GetStringAsync(SourceURI);
return json;
}
}
The above does not work and seems to not return any results properly. I am not sure where I am missing a statement to force the await of a result? I want the RetrieveHolidayDatesFromSource() method to return a string.
The below works fine but it is synchronous and I believe it can be improved upon? Note that the below is synchronous in which I would like to change to Asynchronous but am unable to wrap my head around for some reason.
public string RetrieveHolidayDatesFromSource() {
var result = this.RetrieveHolidayDatesFromSourceAsync();
/** Do Stuff **/
var returnedResult = this.TransformResults(result); /** This is where Result is actually used**/
return returnedResult;
}
private string RetrieveHolidayDatesFromSourceAsync() {
using (var httpClient = new HttpClient()) {
var json = httpClient.GetStringAsync(SourceURI);
return json.Result;
}
}
Am I missing something?
Note: For some reason, when I breakpoint the above Async Method, when it gets to the line var json = await httpClient.GetStringAsync(SourceURI) it just goes out of breakpoint and I can't go back into the method.
Am I missing something?
Yes. Asynchronous code - by its nature - implies that the current thread is not used while the operation is in progress. Synchronous code - by its nature - implies that the current thread is blocked while the operation is in progress. This is why calling asynchronous code from synchronous code literally doesn't even make sense. In fact, as I describe on my blog, a naive approach (using Result/Wait) can easily result in deadlocks.
The first thing to consider is: should my API be synchronous or asynchronous? If it deals with I/O (as in this example), it should be asynchronous. So, this would be a more appropriate design:
public async Task<string> RetrieveHolidayDatesFromSourceAsync() {
var result = await this.DoRetrieveHolidayDatesFromSourceAsync();
/** Do stuff **/
var returnedResult = this.TransformResults(result); /** Where result gets used **/
return returnedResult;
}
As I describe in my async best practices article, you should go "async all the way". If you don't, you won't get any benefit out of async anyway, so why bother?
But let's say that you're interested in eventually going async, but right now you can't change everything, you just want to change part of your app. That's a pretty common situation.
In that case, the proper approach is to expose both synchronous and asynchronous APIs. Eventually, after all the other code is upgraded, the synchronous APIs can be removed. I explore a variety of options for this kind of scenario in my article on brownfield async development; my personal favorite is the "bool parameter hack", which would look like this:
public string RetrieveHolidayDatesFromSource() {
return this.DoRetrieveHolidayDatesFromSourceAsync(sync: true).GetAwaiter().GetResult();
}
public Task<string> RetrieveHolidayDatesFromSourceAsync() {
return this.DoRetrieveHolidayDatesFromSourceAsync(sync: false);
}
private async Task<string> DoRetrieveHolidayDatesFromSourceAsync(bool sync) {
var result = await this.GetHolidayDatesAsync(sync);
/** Do stuff **/
var returnedResult = this.TransformResults(result);
return returnedResult;
}
private async Task<string> GetHolidayDatesAsync(bool sync) {
using (var client = new WebClient()) {
return sync
? client.DownloadString(SourceURI)
: await client.DownloadStringTaskAsync(SourceURI);
}
}
This approach avoids code duplication and also avoids any deadlock or reentrancy problems common with other "sync-over-async" antipattern solutions.
Note that I would still treat the resulting code as an "intermediate step" on the path to a properly-asynchronous API. In particular, the inner code had to fall back on WebClient (which supports both sync and async) instead of the preferred HttpClient (which only supports async). Once all the calling code is changed to use RetrieveHolidayDatesFromSourceAsync and not RetrieveHolidayDatesFromSource, then I'd revisit this and remove all the tech debt, changing it to use HttpClient and be async-only.
public string RetrieveHolidayDatesFromSource() {
var result = this.RetrieveHolidayDatesFromSourceAsync().Result;
/** Do stuff **/
var returnedResult = this.TransformResults(result.Result); /** Where result gets used **/
return returnedResult;
}
If you add .Result to the async call, it will execute and wait for the result to arrive, forcing it to be synchronous
UPDATE:
private static string stringTest()
{
return getStringAsync().Result;
}
private static async Task<string> getStringAsync()
{
return await Task.FromResult<string>("Hello");
}
static void Main(string[] args)
{
Console.WriteLine(stringTest());
}
To address the comment: This works without any problems.

Async and Await in C# [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
So I am trying to get my head wrapped around the async and await in C#, I have read a bunch, seen a few questions here on SO, but I am just not quite sure yet.
So I have written a little sample in hopes you can help me to understand a little clearer what is happening and when to use it. Hopefully my sample is correct.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var c = new MyClass();
c.AccessTheWeb("http://www.google.com");
Console.WriteLine("Waiting");
Console.Read();
}
}
public class MyClass
{
public async Task AccessTheWeb(string url)
{
var result = await GetUrl(url);
Console.Write(result);
}
public async Task<string> GetUrl(string url)
{
string result;
using (var client = new HttpClient())
{
result = await client.GetStringAsync(url);
}
return "Did async task";
}
}
}
I have an +async+ intro on my blog that you may find useful. It has several followup resources at the end that include tips such as:
Console Main usually use Wait on a top-level task.
Asynchronous methods should end with Async.
The program looks Ok to me, I tweaked a few things like waiting for the asynchronous operation to complete. Instead of waiting for user input, I used .Wait()
class Program
{
void Main(string[] args)
{
var c = new MyClass();
Console.WriteLine("Waiting ...");
c.AccessTheWeb("http://www.google.com").Wait();
}
}
public class MyClass
{
public async Task AccessTheWeb(string url)
{
var result = await GetUrl(url);
Console.Write(result);
}
public async Task<string> GetUrl(string url)
{
string result;
using (var client = new HttpClient())
{
result = await client.GetStringAsync(url);
}
return result; // why did you use "Did async task" ?
}
}
Normally when you call an async method the execution continues, with the method being executed in another thread, and you can do other things in the meantime.
You most likely want to check later if the method has completed. You can do so by checking the Task.IsCompleted or Task.TaskStatus properties.
But if for some reason you need to wait for the result of the function before you can move on, you use the await keyword before the method call, to ensure that the execution stops and waits for the method to complete before moving on. This also tells the compiler that it can take a break from executing this particular thread, because it is doing nothing but waiting.
There's a good MSDN article about all this.

Categories

Resources