So I'm trying to write a simple universal app to get the price of bitcoin from the web. I have an async method that I got from here to get the json from a url and put it into a string. Here is where I called the method:
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
CoinPriceBackend CP = new CoinPriceBackend();
string response = await GetFromAPI();
}
And this is the method:
async Task<string> GetFromAPI()
{
try
{
//Create HttpClient
HttpClient httpClient = new HttpClient();
//Define Http Headers
httpClient.DefaultRequestHeaders.Accept.TryParseAdd("application/json");
//Call
string ResponseString = await httpClient.GetStringAsync(
new Uri("https://api.bitcoinaverage.com/ticker/GBP/"));
//Replace current URL with your URL
return ResponseString;
}
catch (Exception ex)
{
return "ERROR: " + ex;
}
}
I get the error
'The 'await' operator can only be used within an async method.
Consider marking this method with the 'async' modifier and changing its return type to 'Task'.'
But the method is async... How can I fix this?
Thanks!
But the method is async
Take a closer look at the error message; it's not talking about GetFromAPI - it's talking about App.
However, as others have pointed out, constructors cannot be marked async.
I'm trying to write a simple universal app
Universal Windows apps - like all other modern platforms - cannot block the UI thread for I/O-based operations. The user experience is just too bad, and there are tests in most app stores to auto-reject apps that do this.
Put another way: App is called (presumably) on application startup. When the user launches your app, it has to start up quickly and show something ASAP. Waiting for a download to complete is simply not an option.
So, to really fix this, you need to just start the download (not waiting for it to complete) and initialize your application to a "loading" state - showing a spinner or "Loading..." message or whatever. Then, when the download completes, update your app to display what you need to.
I have a blog post on async constructors and an article series on async MVVM (if you're doing MVVM), but a really basic approach could look something like this:
public Task Initialization { get; }
public string Value { get; private set { /* code to raise PropertyChanged */ } }
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
CoinPriceBackend CP = new CoinPriceBackend();
Value = "Loading..."; // Initialize to loading state.
Initialization = InitializeAsync();
}
private async Task InitializeAsync()
{
try
{
string response = await GetFromAPI();
...
Value = response; // Update data-bound value.
}
catch (Exception ex)
{
... // Display to user or something...
}
}
When you use an await within a function you should define the function as async.
But for App() constructor you will be unable to do that. You can defined another function from which you can call your function which return string.
Like this
public App()
{
CallApi();
}
private async void CallApi()
{
response = await GetFromAPI();
}
C# does not allow constructors to be marked as async.
You have three main options:
1) refactor to call this method in async event handler;
2) spawn a new thread using Task.Run and run async code there. This could lead to issues of marshalling result back to UI thread and assigning value to some UI element;
3) make it synchronous (blocking) call. This probably is the easiest option.
You will have to make following changes.
string response = GetFromAPI().Result;
Note that this will probably cause deadlock as Task will try to reaume in the main thread, which is already locked by call to '.Result', therefore you need another change. Also, there is no point
Task<string> GetFromAPI()
{
....
return httpClient.GetStringAsync(new Uri("https://api.bitcoinaverage.com/ticker/GBP/")).ConfigureAwait(false);
...
}
Related
Suppose I have written a library which relies on async methods:
namespace MyLibrary1
{
public class ClassFromMyLibrary1
{
public async Task<string> MethodFromMyLibrary1(string key, Func<string, Task<string>> actionToProcessNewValue)
{
var remoteValue = await GetValueByKey(key).ConfigureAwait(false);
//do some transformations of the value
var newValue = string.Format("Remote-{0}", remoteValue);
var processedValue = await actionToProcessNewValue(newValue).ConfigureAwait(false);
return string.Format("Processed-{0}", processedValue);
}
private async Task<string> GetValueByKey(string key)
{
//simulate time-consuming operation
await Task.Delay(500).ConfigureAwait(false);
return string.Format("ValueFromRemoteLocationBy{0}", key);
}
}
}
I followed the recommendations of using ConfigureAwait(false) (like in this post) everywhere in my library. Then I use it in synchronous way from my test app and get a failure:
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button1_OnClick(object sender, RoutedEventArgs e)
{
try
{
var c = new ClassFromMyLibrary1();
var v1 = c.MethodFromMyLibrary1("test1", ActionToProcessNewValue).Result;
Label2.Content = v1;
}
catch (Exception ex)
{
System.Diagnostics.Trace.TraceError("{0}", ex);
throw;
}
}
private Task<string> ActionToProcessNewValue(string s)
{
Label1.Content = s;
return Task.FromResult(string.Format("test2{0}", s));
}
}
}
The failure is:
WpfApplication1.vshost.exe Error: 0 :
System.InvalidOperationException: The calling thread cannot access
this object because a different thread owns it. at
System.Windows.Threading.Dispatcher.VerifyAccess() at
System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object
value) at System.Windows.Controls.ContentControl.set_Content(Object
value) at WpfApplication1.MainWindow.ActionToProcessNewValue(String
s) in
C:\dev\tests\4\WpfApplication1\WpfApplication1\MainWindow.xaml.cs:line
56 at
MyLibrary1.ClassFromMyLibrary1.d__0.MoveNext()
in
C:\dev\tests\4\WpfApplication1\WpfApplication1\MainWindow.xaml.cs:line
77
--- End of stack trace from previous location where exception was thrown --- at
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task) at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at WpfApplication1.MainWindow.d__1.MoveNext() in
C:\dev\tests\4\WpfApplication1\WpfApplication1\MainWindow.xaml.cs:line
39 Exception thrown: 'System.InvalidOperationException' in
WpfApplication1.exe
Obviously the error happens because the awaiters in my library discard current WPF context.
From the other hand, after removing the ConfigureAwait(false) everywhere in the library I obviously get a deadlock instead.
There is more detailed example of code which explains some constraints that I have to deal with.
So how can I address this issue? What is the best approach here? Do I still need to follow the best practice regarding ConfigureAwait?
PS, In real scenario I have many classes and methods therefore tons of such async calls in my library. It's nearly impossible to find out if some particular async call requires context or not (see comments to #Alisson response) to fix it. I don't care about performance though, at least at this point. I'm looking for some general approach to address this issue.
Normally a library will document if a callback will be guaranteed to be on the same thread that called it, if it is not documented the safest option will be to assume it does not. Your code example (and the 3rd party you are working with from what I can tell from your comments) fall under the category of "Not guaranteed". In that situation you just need to check if you need to do a Invoke from inside the callback method and do it, you can call Dispatcher.CheckAccess() and it will return false if you need to invoke before using the control.
private async Task<string> ActionToProcessNewValue(string s)
{
//I like to put the work in a delegate so you don't need to type
// the same code for both if checks
Action work = () => Label1.Content = s;
if(Label1.Dispatcher.CheckAccess())
{
work();
}
else
{
var operation = Label1.Dispatcher.InvokeAsync(work, DispatcherPriority.Send);
//We likely don't need .ConfigureAwait(false) because we just proved
// we are not on the UI thread in the if check.
await operation.Task.ConfigureAwait(false);
}
return string.Format("test2{0}", s);
}
Here is a alternate version with a syncronous callback instead of a async one.
private string ActionToProcessNewValue(string s)
{
Action work = () => Label1.Content = s;
if(Label1.Dispatcher.CheckAccess())
{
work();
}
else
{
Label1.Dispatcher.Invoke(work, DispatcherPriority.Send);
}
return string.Format("test2{0}", s);
}
Here is another version if you wanted to get the value from Label1.Content instead of assigning it, this also does not need to use async/await inside the callback.
private Task<string> ActionToProcessNewValue(string s)
{
Func<string> work = () => Label1.Content.ToString();
if(Label1.Dispatcher.CheckAccess())
{
return Task.FromResult(work());
}
else
{
return Label1.Dispatcher.InvokeAsync(work, DispatcherPriority.Send).Task;
}
}
IMPORTANT NOTE: all of these methods will cause your program to deadlock if you don't get rid of the .Result in the button click handler, the Dispatcher.Invoke or the Dispatcher.InvokeAsync in the callback will never start while it is waiting for .Result to return and .Result will never return while it is waiting for the callback to return. You must change the click handler to be async void and do a await instead of the .Result.
Actually, you're receiving a callback in your ClassFromMyLibrary1 and you can't assume what it'll do (like updating a Label). You don't need ConfigureAwait(false) in your class library, as the same link you provided gives us an explanation like this:
As asynchronous GUI applications grow larger, you might find many
small parts of async methods all using the GUI thread as their
context. This can cause sluggishness as responsiveness suffers from
"thousands of paper cuts".
To mitigate this, await the result of ConfigureAwait whenever you can.
By using ConfigureAwait, you enable a small amount of parallelism:
Some asynchronous code can run in parallel with the GUI thread instead
of constantly badgering it with bits of work to do.
Now take a read here:
You should not use ConfigureAwait when you have code after the await
in the method that needs the context. For GUI apps, this includes any
code that manipulates GUI elements, writes data-bound properties or
depends on a GUI-specific type such as Dispatcher/CoreDispatcher.
You're doing exactly the opposite. You're trying to update GUI in two points, one in your callback method, and another here:
var c = new ClassFromMyLibrary1();
var v1 = c.MethodFromMyLibrary1("test1", ActionToProcessNewValue).Result;
Label2.Content = v1; // updating GUI...
That's why removing ConfigureAwait(false) solves your problem. Also, you can make your button click handler async and await your ClassFromMyLibrary1 method call.
In my opinion, you should redesign your library API to not mix a callback-based API with a Task-based API. At least in your example code there's no compelling case to be made to do that and you've nailed one reason not do do that - it is hard to control the context in which your callback runs.
I'd change your library API to be like so:
namespace MyLibrary1
{
public class ClassFromMyLibrary1
{
public async Task<string> MethodFromMyLibrary1(string key)
{
var remoteValue = await GetValueByKey(key).ConfigureAwait(false);
return remoteValue;
}
public string TransformProcessedValue(string processedValue)
{
return string.Format("Processed-{0}", processedValue);
}
private async Task<string> GetValueByKey(string key)
{
//simulate time-consuming operation
await Task.Delay(500).ConfigureAwait(false);
return string.Format("ValueFromRemoteLocationBy{0}", key);
}
}
}
And call it like so:
private async void Button1_OnClick(object sender, RoutedEventArgs e)
{
try
{
var c = new ClassFromMyLibrary1();
var v1 = await c.MethodFromMyLibrary1("test1");
var v2 = await ActionToProcessNewValue(v1);
var v3 = c.TransformProcessedValue(v2);
Label2.Content = v3;
}
catch (Exception ex)
{
System.Diagnostics.Trace.TraceError("{0}", ex);
throw;
}
}
private Task<string> ActionToProcessNewValue(string s)
{
Label1.Content = s;
return Task.FromResult(string.Format("test2{0}", s));
}
In my Xamarin application, after user clicks some button I want to make a phone call and then return to my app (ideally to the same place in the code).
Something like this:
async Task button_click()
{
string s = "200-345-6789";
// await Device.OpenUri("tel:" + s); // can't await this
ShowAlert("The number " + s + " was called");
}
Originally I tried Device.OpenUri, but it's not awaitable.
On Android, StartActivityWithResult worked well for me. I define TaskCompletionSource, start activity with an intent of ActionCall, and inside OnActivityResult function I flag my task as completed, which returns the flow back to the original function.
But on iOS, I can't find anything similar. What would you suggest?
Note: This is a common Xamarin iOS async uri pattern and do not claim it as my own as it is used in a number OSS libraries:
public Task<bool> LaunchUriAsync(Uri uri)
{
var completion = new TaskCompletionSource<bool>();
var sharedApp = UIApplication.SharedApplication;
sharedApp.BeginInvokeOnMainThread(() =>
{
try
{
var url = NSUrl.FromString(uri.ToString()) ?? new NSUrl(uri.Scheme, uri.Host, uri.LocalPath);
var result = sharedApp.CanOpenUrl(url) && sharedApp.OpenUrl(url);
completion.SetResult(result);
}
catch (Exception exception)
{
completion.SetException(exception);
}
});
return completion.Task;
}
Examples:
await LaunchUriAsync(new Uri("mailto:demo#example.com"));
await LaunchUriAsync(new Uri("tel:555-555-5555"));
await LaunchUriAsync(new Uri("https://www.google.com"));
await LaunchUriAsync(new Uri("sms:555-555-5555"));
After messing with this for some more hours, I found the solution - so I thought I'd post it for others to benefit.
What I did is simulation of something similar to Android's OnActivityResult.
Inside my AppDelegate class I define an event which is fired from its OnActivated function.
Now, inside my function I subscribe to this event passing to the delegate a TaskCompletionSource which I define. Then I call Device.OpenUri("tel:" + phoneNum). The phone call is made, and after it ends the user is returned to my app, AppDelegate.OnActivated fires my event, my delegate is called and I can mark my task as completed by calling SetResult. This makes possible to await this function.
You can use the telprompt:<phone-number> scheme, this will return the user to your app after the call is finished.
Just one remark, this scheme is not officially support by Apple so they might remove it a some point.
There are only two ways to dial a number on iOS either tel:<phone-number> or telprompt:<phone-number>. There are no other ways.
I have a webpage with a list of recipes. In my code, I loop through the page and download each recipe. Here is a pseudo code of what I am doing :
//This is the Recipe class
//The constructor accepts a link to the recipe
//This method scrapes the recipe
public Task ScrapeAsync(){
return Task.Run(async () => {
string WebPage;
WebRequest request = WebRequest.Create(link);
request.Method = "GET";
using (WebResponse response = await request.GetResponseAsync())
using (StreamReader reader = new StreamReader(response.GetResponseStream())) {
WebPage = await reader.ReadToEndAsync();
}
//Non - async code here which is used to scrape the webpage
}
}
I used Task.Run because there are both async and blocking code in the Method.
//This is the RecipePage class
//This method scrapes the page
public Task GetRecipeListAsync(){
return Task.Run(async () => {
//I get the page using WebRequest and WebResponse in the same way as above
//Non - async/blocking code here which scrapes the page and finds links to recipes. I do await Recipe.ScrapeAsync() somewhere here.
//And I add the recipe objects to a public list in this class
}
}
In the form, it loops through a list of pages and do await RecipePage.GetRecipeList() and other things.
Here's where the for loop is:
private async void go_Click(object sender, EventArgs e){
for (int i = (int)startingPageNUD.Value; i <= (int)finishingPageNUD.Value; ++i) {
RecipePage page = new RecipePage(page + i);
await page.GetRecipeListAsync();
//Some other code here
}
}
My problem is that whenever an exception happens in the ScrapeAsync method, Visual Studio 2013 points to Application.Run(new Form1())
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
and tells me that Reflection.TargetInvocationException has occured. It does not show the actual exception in my code. For example, if I get a NullReferenceException in the code, it does not show that.
Because of this, I am having to write both async and non-async code and use non-async code to debug. Is there any way to solve this?
I have another question too. Am I using async/await and Task in the correct way?
Am I using async/await and Task in the correct way?
Pretty close. I don't see a need for Task.Run in this scenario (it should only be used to move CPU-intensive operations off the UI thread, and HTML scraping is usually fast enough to stay on the UI without any adverse effects).
The other recommendation I'd make is to have async Task methods return values as much as possible, instead of modifying member variables as side effects. In your case, consider having ScrapeAsync return its own list instead of updating a shared list, and having the calling code do the list merging.
Regarding your exception, TargetInvocationException will have an InnerException with the details. Exceptions in async void event handlers are managed in practically the same say as exceptions in regular void event handlers: if one escapes the event handler, then it goes to the application main loop. If you don't want this, you'll have to catch it (for both synchronous and asynchronous handlers).
Okay. Thanks to your edits I now can answer.
Your problem is this function:
private async void go_Click(object sender, EventArgs e){
for (int i = (int)startingPageNUD.Value; i <= (int)finishingPageNUD.Value; ++i) {
RecipePage page = new RecipePage(page + i);
await page.GetRecipeListAsync();
//Some other code here
}
}
The issue is that the function returns to what ever calls it once it reaches the await. Now if page.GetRecipeListAsync(); throws a exception, this exception is thrown inside the continuation handler. This handler is executed in the task queue of your UI. A exception thrown there crashes the task loop of your UI and this has all sorts of funny effects including strange exceptions.
In a async void function you should always handle any incoming exceptions by wrapping all code inside into a try…catch. If you crash the application if a exception occurs there or not is yours to decide.
The general way the things work is that any exception thrown inside a Task and by extend in a async function are thrown again by the await. But the async void functions are not awaited anywhere, so that does not work.
Regarding the usage of the async. I don't think you need to wrap every function into a Task but you can do that. Usually you don't need to force it into the background like this.
Encapsulate the getRecipeList code inside a try/catch.
In the catch code, get exception message and stack trace and assign them to variable(s) of Recipe class that you will test/display in your main thread when action is completed.
private string TheException = "" ;
public Task GetRecipeListAsync()
{
TheException = "" ;
Task result = Task.Run(async () =>
{
try
{
//I get the page using WebRequest and WebResponse in the same way as above
...
}
catch (Exception Ex)
}
if (TheException!="") MessageBox.show(TheException) ;
// or Throw an exception with
return result ;
}
you may also test "TheExceptio" in the GoClick procedure.
I have created a webservice and a method as follows:
[WebMethod]
public bool GetMasterExit(int RoomID)
{
if(GameList[RoomID][0] == "\0")
return true;
else
return false;
}
And then I call this from WP client using the following way but there is a problem that I want the main process blocked until the webservice returns the value I want but in this way the value is wrong for delay.
I have tried to use the Await but I got an error that "cannot await void", so Anyone knows how to solve this problem?
public void Test()
{
ServiceSoapClient GameClient = new ServiceSoapClient();
GameClient.GetMasterExitCompleted += _clientGetMasterExitCompleted;
GameClient.GetMasterExitAsync(RoomID);
Console.WriteLine(MasterExit);
}
public void _clientGetMasterExitCompleted(object sender, GetMasterExitCompletedEventArgs e)
{
MasterExit = e.Result;
}
I want the main process blocked until the webservice returns the value
This is an incorrect approach. Especially on mobile platforms such as WP, you're not allowed to block the UI like that.
The proper solution is to use await. Follow the Task-based Asynchronous Pattern and write an EAP wrapper called GetMasterExitTaskAsync.
If you are willing to use await then you must add modifier async to your function signature.Hope this helps.
Use async and await like this:
public async void Test()
{
ServiceSoapClient GameClient = new ServiceSoapClient();
GameClient.GetMasterExitCompleted += _clientGetMasterExitCompleted;
await GameClient.GetMasterExitAsync(RoomID);
Console.WriteLine(MasterExit);
}
I'm busy with a windows phone application that of course uses silverlight. This means that calling any webservices has to be done asynchronously, and since this is all good and well in regards to best practice in preventing your entire app in hanging when waiting for a resource, I'm still stuck in the "synchronous mindset"...
Because the way I see it now is that you end up having 2 methods that needs to handle one function, e.g:
1)The method that actually calls the webservice:
public void myAsyncWebService(DownloadStringCompletedEventHandler callback)
{
//Url to webservice
string servletUrl = "https://deangrobler.com/someService/etc/etc"
//Calls Servlet
WebClient client = new WebClient();
client.DownloadStringCompleted += callback;
client.DownloadStringAsync(new Uri(servletUrl, UriKind.Absolute));
}
2) and the method that handles the data when it eventually comes back:
private void serviceReturn(object sender, DownloadStringCompletedEventArgs e)
{
var jsonResponse = e.Result;
//and so on and so forth...
}
So instead of having to just create and call a single method that goes to the webservice, gets the returned result and sent it back to me like this:
public string mySyncWebService(){
//Calls the webservice
// ...waits for return
//And returns result
}
I have to in a Class call myAsyncWebService, AND create another method in the calling class that will handle the result returned by myAsyncWebService. Just, in my opinion, creates messy code. With synchronous calls you could just call one method and be done with it.
Am I just using Asynchronous calls wrong? Is my understanding wrong? I need some enlightment here, I hate doing this messy-async calls. It makes my code too complex and readability just goes to... hell.
Thanks for anyone willing to shift my mind!
You have to turn your mind inside out to program asynchronously. I speak from experience. :)
Am I just using Asynchronous calls wrong? Is my understanding wrong?
No. Asynchronous code is fairly difficult to write (don't forget error handling) and extremely difficult to maintain.
This is the reason that async and await were invented.
If you're able to upgrade to VS2012, then you can use Microsoft.Bcl.Async (currently in beta) to write your code like this:
string url1 = "https://deangrobler.com/someService/etc/etc";
string jsonResponse1 = await new WebClient().DownloadStringTaskAsync(url1);
string url2 = GetUriFromJson(jsonResponse1);
string jsonResponse2 = await new WebClient().DownloadStringTaskAsync(url2);
Easy to write. Easy to maintain.
Async is like when you make a telephone call and get an answering machine, if you want a return call you leave your number. The first method is your call asking for data, the second is the "number" you've left for the return call.
It all becomes much easier and readable if you use lambdas instead. This also enables you to access variables declared in the "parent" method, like in the following example:
private void CallWebService()
{
//Defined outside the callback
var someFlag = true;
var client = new WebClient();
client.DownloadStringCompleted += (s, e) =>
{
//Using lambdas, we can access variables defined outside the callback
if (someFlag)
{
//Do stuff with the result.
}
};
client.DownloadStringAsync(new Uri("http://www.microsoft.com/"));
}
EDIT: Here is another example with two chained service calls. It still isn't very pretty, but imho it is a little more readable than the OPs original code.
private void CallTwoWebServices()
{
var client = new WebClient();
client.DownloadStringCompleted += (s, e) =>
{
//1st call completed. Now make 2nd call.
var client2 = new WebClient();
client2.DownloadStringCompleted += (s2, e2) =>
{
//Both calls completed.
};
client2.DownloadStringAsync(new Uri("http://www.google.com/"));
};
client.DownloadStringAsync(new Uri("http://www.microsoft.com/"));
}
To avoid creating messy code, if you can't use the async / await pattern because you are on older framework, you will find helpful check CoRoutines in their Caliburn Micro implemantation. With this pattern you create an enumerable yielding at each turn a new asynchronous segment to execute: by the reader point of view asynchronous steps appear as a sequence, but walking among the steps ( so yielding the next one ) is done externally by asynchronously wait the single task. It is a nice pattern easy to implement and really clear to read.
BTW if you don't want to use Caliburn Micro as your MVVM tool because you are using something else, you can use just the coroutine facility, it is very insulated inside the framework.
Let me just post some code from an example in this blog post.
public IEnumerable<IResult> Login(string username, string password)
{
_credential.Username = username;
_credential.Password = password;
var result = new Result();
var request = new GetUserSettings(username);
yield return new ProcessQuery(request, result, "Logging In...");
if (result.HasErrors)
{
yield return new ShowMessageBox("The username or password provided is incorrect.", "Access Denied");
yield break;
}
var response = result.GetResponse(request);
if(response.Permissions == null || response.Permissions.Count < 1)
{
yield return new ShowMessageBox("You do not have permission to access the dashboard.", "Access Denied");
yield break;
}
_context.Permissions = response.Permissions;
yield return new OpenWith<IShell, IDashboard>();
}
Isn't it easy to read? But it is is actually asynchronous: each yield steps are executed in an asynchronous manner and the execution flow again after the yield statement as soon the previous task completed.
With synchronous calls you could just call one method and be done with it.
Sure, but if you do that from the UI thread you will block the entire UI. That is unacceptable in any modern application, in particular in Silverlight applications running in the browser or in the phone. A phone that is unresponsive for 30 seconds while a DNS lookup times out is not something anybody wants to use.
So on the UI thread, probably because the user did some action in the UI, you start an asynchronous call. When the call completes a method is called on a background thread to handle the result of the call. This method will most likely update the UI with the result of the asynchronous call.
With the introduction of async and await in .NET 4.5 some of this "split" code can be simplified. Luckily async and await is now available for Windows Phone 7.5 in a beta version using the NuGet package Microsoft.Bcl.Async.
Here is a small (and somewhat silly) example demonstrating how you can chain two web service calls using async. This works with .NET 4.5 but using the NuGet package linked above you should be able to do something similar on Windows Phone 7.5.
async Task<String> GetCurrencyCode() {
using (var webClient = new WebClient()) {
var xml = await webClient.DownloadStringTaskAsync("http://freegeoip.net/xml/");
var xElement = XElement.Parse(xml);
var countryName = (String) xElement.Element("CountryName");
return await GetCurrencyCodeForCountry(countryName);
}
}
async Task<String> GetCurrencyCodeForCountry(String countryName) {
using (var webClient = new WebClient()) {
var outerXml = await webClient.DownloadStringTaskAsync("http://www.webservicex.net/country.asmx/GetCurrencyByCountry?CountryName=" + countryName);
var outerXElement = XElement.Parse(outerXml);
var innerXml = (String) outerXElement;
var innerXElement = XElement.Parse(innerXml);
var currencyCode = (String) innerXElement.Element("Table").Element("CurrencyCode");
return currencyCode;
}
}
However, you still need to bridge between the UI thread and the async GetCurrencyCode. You can't await in an event handler but you can use Task.ContinueWith on the task returned by the async call:
void OnUserAction() {
GetCurrencyCode().ContinueWith(GetCurrencyCodeCallback);
}
void GetCurrencyCodeCallback(Task<String> task) {
if (!task.IsFaulted)
Console.WriteLine(task.Result);
else
Console.WriteLine(task.Exception);
}