I'm building a Metro App.
In the MainPage.xaml.cs, I instantiate Album as follows:
Album album = new Album(2012); //With the album ID as its parameter.
ListView1.ItemsSource = album.Songs;
In the Album.cs, the constructor is as follows:
public Album(int ID)
{
this.ID = ID;
Initialize(); //Serves as a wrapper because I have to call httpClient.GetStreamAsync() and "async" doesn't work for the constructor.
}
Finally, the Initialize method:
private async void Initialize()
{
//...some code...
HttpClient cli = new HttpClient();
Stream SourceStream = await HttpClient.GetStreamAsync("http://contoso.com");
//...some code...
this.Songs = Parse(SourceStream);
}
The problem is when it runs to GetStreamAsync, it then goes to ListView1.ItemsSource = album.Songs directly with the album.Songs null.
Is there any quick solution to this problem?
Yes. The whole point of async and await are that you don't block. Instead, if you're "awaiting" an operation which hasn't completed yet, a continuation is scheduled to execute the rest of the async method, and control is returned to the caller.
Now because your method has a type of void, you have no way of knowing when that's even finished - if you returned Task (which wouldn't require any change in the body of the method) you'd at least be able to work out when it had finished.
It's not really clear what your code looks like, but fundamentally you should only be trying to set the ItemsSource after initialization has finished. You should probably have your MainPage code in an async method too, which would look something like:
Album album = new Album(2012);
ListView1.ItemsSource = await album.GetSongsAsync();
Your GetSongs() call would then be:
private async Task<List<Song>> GetSongsAsync()
{
//...some code...
HttpClient cli = new HttpClient();
Stream SourceStream = await HttpClient.GetStreamAsync("http://contoso.com");
//...some code...
return Parse(SourceStream);
}
This means Songs would no longer be a property of Album itself, although you could add it in for caching purposes if you wanted to.
Make Songs property return Task<List<Song>> and await at ListView1.ItemsSource = await album.Songs;
Related
This question already has answers here:
Can constructors be async?
(15 answers)
Closed 25 days ago.
I've read many explanations but none of them made sense to me.
I'm doing this in Xamarin.Forms:
public class SomeClass
{
public SomeClass
{
var request = new GeolocationRequest(GeolocationAccuracy.High, TimeSpan.FromSeconds(10));
var cts = new CancellationTokenSource();
var location = Task.Run<Location>(async () => await Geolocation.GetLocationAsync(request, cts.Token));
var userLat = location.Latitude; // doesn't work
var userLon = location.Longitude; // doesn't work
}
}
The reason I'm doing this is that I'm trying to load all the methods I need such as getting the user's location, show it on the map, load up some pins etc. as soon as the Xamarin.Forms.Maps map appears.
I know it's bad practice from what you guys answered so I'm working on changing that but I'm still having a hard time understanding how to do it differently in the sense of it's confusing. But I'm reading your articles and links to make sure I understand.
I tried to run Task.Run(async () => await) on many methods, and tried to save their values in variables but I can't get the returned value and that's what made me post this question, I need to change my code.
I know could get the returned value using Task.Result() but I've read that this was bad.
How to get the UI to load and wait on the ViewModel to do what it has to do, and then tell the UI to then use whatever the ViewModel is giving him when it is ready ?
You mentioned in a comment to another answer that you can't do it async because this code is in a constructor. In that case, it is recommended to move the asynchronous code into a separate method:
public class MyClass
{
public async Task Init()
{
var request = new GeolocationRequest(GeolocationAccuracy.High, TimeSpan.FromSeconds(10));
var cts = new CancellationTokenSource();
var location = await Geolocation.GetLocationAsync(request, cts.Token);
var userLat = location.Latitude;
var userLon = location.Longitude;
}
}
You can use it the following way:
var myObject = new MyClass();
await myObject.Init();
The other methods of this class could throw an InvalidOperationException if Init() wasn't called yet. You can set a private boolean variable wasInitialized to true at the end of the Init() method. As an alternative, you can make your constructor private an create a static method that creates your object. By this, you can assure that your object is always initialized correctly:
public class MyClass
{
private MyClass() { }
public async Task<MyClass> CreateNewMyClass()
{
var result = new MyClass();
var request = new GeolocationRequest(GeolocationAccuracy.High, TimeSpan.FromSeconds(10));
var cts = new CancellationTokenSource();
var location = await Geolocation.GetLocationAsync(request, cts.Token);
result.userLat = location.Latitude;
result.userLon = location.Longitude;
return result;
}
}
I think it could be this:
public async Task SomeMethodAsync()
{
var request = new GeolocationRequest(GeolocationAccuracy.High, TimeSpan.FromSeconds(10));
var cts = new CancellationTokenSource();
var location = await Geolocation.GetLocationAsync(request, cts.Token);
var userLat = location.Latitude;
var userLon = location.Longitude;
}
Not that methods which contain await calls should be marked as async. If you need to return something from this method then the return type will be Task<TResult>.
Constructors cannot be marked with async keyword. And it's better not to call any async methods from constructor, because it cannot be done the right way with await. As an alternative please consider Factory Method pattern. Check the following article of Stephen Cleary for details: Async OOP 2: Constructors.
The normal way to retrieve results from a Task<T> is to use await. However, since this is a constructor, there are some additional wrinkles.
Think of it this way: asynchronous code make take some time to complete, and you can never be sure how long. This is in conflict with the UI requirements; when Xamarin creates your UI, it needs something to show the user right now.
So, your UI class constructor must complete synchronously. The normal way to handle this is to (immediately and synchronously) create the UI in some kind of "loading..." state and start the asynchronous operation. Then, when the operation completes, update the UI with that data.
I discuss this in more detail in my article on async data binding.
Do the asynchronous work before constructing the object and pass in the data to the constructor. I suggest a factory.
class MyFactory : IMyFactory
{
public async Task<MyClass> GetMyClass()
{
var request = new GeolocationRequest(GeolocationAccuracy.High, TimeSpan.FromSeconds(10));
var cts = new CancellationTokenSource();
var location = Task.Run<Location>(async () => await Geolocation.GetLocationAsync(request, cts.Token));
return new MyClass(location);
}
}
class MyClass
{
public MyClass(Location location)
{
var userLat = location.Latitude;
var userLon = location.Longitude;
//etc....
}
}
To create an instance, instead of
var x = new MyClass();
you'd call
var factory = new MyFactory();
var x = await factory.GetMyClass();
The nice thing about this approach is that you can mock the factory (e.g. for unit tests) in a way that does not depend on the external service.
Does it make sense to call only one async private method and await for it in another async method?
Example:
private async Task<string> ReadMyFileAsync()
{
var streamReader = new StreamReader(#"c:\myFile.txt")
return await streamReader.ReadToEndAsync(); // <-- Does it make sense for me here to await for only onething, while the caller of the method ReadMyFileAsync is already an async method?
// By ignoring that the stream should be disposed...
}
private string ReadMyFile()
{
var streamReader = new StreamReader(#"c:\myFile.txt")
return streamReader.ReadToEnd();
// By ignoring that the stream should be disposed...
}
public async void OnFileChangedHandler()
{
// Some work...
var myText = await ReadMyFileAsync(); <-- Does it make any difference whether I called `await ReadMyFileAsync()` or `ReadMyFile()`?
var someThingElse = await SomeThingElse(...);
// Some work...
}
In the scenario above, what I guess, even if the method ReadMyFileAsync was called in its syncronous version (without using async and by using ReadToEnd() instead of await ReadToEndAsync()), it will keep acting the same, because the caller method is an async method. Which means in my opinion, this will make sense only if I am trying to read multiple files in paralell (see the following as example), is that right?
private async Task<string> ReadMyFileAsync() // <-- This makes sense for me
{
var streamReader1 = new StreamReader(#"c:\myFile1.txt");
var streamReader2 = new StreamReader(#"c:\myFile2.txt");
var streamReader3 = new StreamReader(#"c:\myFile3.txt");
var myText1Task = streamReader1.ReadToEndAsync();
var myText2Task = streamReader2.ReadToEndAsync();
var myText3Task = streamReader3.ReadToEndAsync();
return await myText1Task + await myText2Task + await myText3Task;
// By ignoring that the streams should be disposed...
}
So the question is simply, in the first block of code, does it make any difference whether I called ReadMyFileAsync or ReadMyFile?
Update: The whole question simplified is:
If I am going to await for the async method ReadMyFileAsync inside my async method OnFileChangedHandler, why would I use ReadMyFileAsync over ReadMyFile?
It depends. If you really only call one other method and you have no side effects, then you could just return the Task instead of awaiting it and returning the result wrapped in a task.
However, even in your example, you have side effects. You need to .Dispose something and you need to know when to do that. So you cannot just return the task, you need to wait until it's finished, then dispose your resources and then return the result of the finished task. Since it's "not that simple" even in your own boiled down example, the answer is: it does make sense. You have to decide case-by-case.
Sometimes you can just pass the task along, then the method does not need to be async at all, it just needs to return a Task and sometimes you need to do things based on the timing of tasks (i.e. do this only after that other thing is finished) and then you need to use async methods because you want to await results.
Yes, you should prefer async methods over sync because async methods doesn't block the executing thread. In UI apps it means that UI won't freeze. In Server apps it means that your server will be able to run more concurrent work without starving the threads.
In my service layer I wanted to fire multiple methods asynchronously and await for their results.
I tried with one at a time and it is erroring out.
In my service class I called the method like
var _validChapterCodesTask = gd.validateChapterCodeDetails(_input1);
await Task.WhenAll(_validChapterCodesTask);
var _chapterCodeResult = await _validChapterCodesTask;
And in DAL class the method definition looks like
public async Task<IEnumerable<ChapterCodeValidationOutput>> validateChapterCodeDetails(GroupMembershipValidationInput gmvi)
{
Repository rep = new Repository();
if (!gmvi._chapterCodes.All(x => x.Equals("")))
{
var _validChapterCodes = await rep.ExecuteStoredProcedureAsync<Entities.Upload.ChapterCodeValidationOutput>(SQL.Upload.UploadValidation.getChapterCodeValidationSQL(gmvi._chapterCodes),null);
return _validChapterCodes;
}
else
return new List<ChapterCodeValidationOutput>();
}
Error message
Error 208 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<ARC.Donor.Business.Upload.GroupMembershipValidationOutput>. C:\Users\m1034699\Desktop\Stuart_Upgrade_2.1_New Approach\Stuart_Export_Upload_v2.1\Stuart Web Service\ARC.Donor.Service\Upload\UploadValidationServices.cs 34 13 ARC.Donor.Service
in lines
await Task.WhenAll(_validChapterCodesTask);
var _chapterCodeResult = await _validChapterCodesTask;
What am I doing wrong ?
The error message is very explicit. It is telling you that you're Service class method is incorrectly attempting to use the async keyword. In order to fix this, you should be using "Async all the way" as defined in Stephen Cleary's post on MSDN as a best practice.
For example, if you're service class has a method body that is working with Task or Task<T>, or attempting to use the await keyword the method signature for this corresponding method body must be async (as the async keyword enables a method to use the await keyword). Additionally this method itself should also be Task or Task<T> returning, with very few exceptions to that rule.
Personally, I would alter your DAL class to simply return the operation that represents the asynchronous work without actually awaiting it. If you think about it, the body of the validateChapterCodeDetails method does not actually need to do anything with the results, it just needs to return them (instead of materializing them there). Consider the following:
public Task<IEnumerable<ChapterCodeValidationOutput>>
validateChapterCodeDetails(GroupMembershipValidationInput gmvi)
{
var rep = new Repository();
return gmvi._chapterCodes.All(x => x.Equals(""))
? new List<ChapterCodeValidationOutput>()
: rep.ExecuteStoredProcedureAsync
<Entities.Upload.ChapterCodeValidationOutput>
(SQL.Upload.UploadValidation
.getChapterCodeValidationSQL(gmvi._chapterCodes),null)
}
Since your Task<IEnumerable<ChapterCodeValidationOutput>> variable has already been awaited, you can access the .Result property to get what you're looking for.
Then in your Service class your method would look like this:
public async Task ConsumeAsync()
{
var _validChapterCodesTask = gd.validateChapterCodeDetails(_input1);
await Task.WhenAll(_validChapterCodesTask);
var _chapterCodeResult = _validChapterCodesTask.Result;
// Do something with it...
}
Here is a .NET fiddle that should help to exemplify this for you better.
NOTE
I would also caution using IEnumerable as it pertains to your repo, you should ensure that the results from the Database are not occurring via deferred execution, otherwise you risk the potential for connection issues, i.e.; unintentionally leaving a connection open, or not properly closing one.
In the Service class where you call
var _validChapterCodesTask = gd.validateChapterCodeDetails(_input1);
await Task.WhenAll(_validChapterCodesTask);
var _chapterCodeResult = await _validChapterCodesTask;
add a async to the method signature where await Task.WhenAll(_validChapterCodesTask); is called. And when this method also has a return type you have to wrap this type in a Task like the exception shows:
Task<ARC.Donor.Business.Upload.GroupMembershipValidationOutput>
E.g. if you have the following method:
public GroupMemberShipValidationOutput validate(..) {
...
await Task.WhenAll(_validChapterCodesTask);
...
}
You have to change the method signature to:
public async Task<GroupMemberShipValidationOutput> validate(..) {
...
await Task.WhenAll(_validChapterCodesTask);
...
}
I have a Web API service that is used to retrieve and update a specific set of data (MyDataSet objects), and I am running into some confusion in using async/await when performing the following events:
Update MyDataSet with new values
Get MyDataSet (but only after the new values have been updated)
In my client, I have something similar to the following:
Harmony.cs
private async Task<string> GetDataSet(string request)
{
using(var httpClient = new HttpClient())
{
httpClient.baseAddress = theBaseAddress;
HttpResponseMessage response = await httpClient.GetAsync(request);
response.EnsureSuccessStatusCode();
return response.Content.ReadAsStringAsync().Result;
}
}
private async Task PostDataSet<T>(string request, T data)
{
using (var httpClient = new HttpClient())
{
client.BaseAddress = new Uri(theBaseAddress);
HttpResponseMessage response = await client.PostAsJsonAsync<T>(request, data);
response.EnsureSuccessStatusCode();
}
}
internal MyDataSet GetMyDataSetById(int id)
{
string request = String.Format("api/MyDataSet/GetById/{0}", id);
return JsonConvert.DeserializeObject<MyDataSet>(GetDataSet(request).Result);
}
internal void UpdateDataSet(MyDataSet data)
{
PostDataSet("api/MyDataSet/Update", data);
}
HarmonyScheduler.cs
internal void ScheduleDataSet()
{
MyDataSet data = ...
harmony.UpdateDataSet(data);
MyDataSet data2 = harmony.GetMyDataSetById(data.Id);
}
There is a compiler warning in Harmony.cs UpdateDataSet because the call is not awaited and execution will continue before the call is completed. This is affecting the program execution, because data2 is being retrieved before the update is taking place.
If I were to make UpdateDataSet async and add an await to it, then it just moves things up the stack a level, and now HarmonyScheduler gets the warning about not being awaited.
How do I wait for the update to be complete before retrieving data2, so that I will have the updated values in the data2 object?
How do I wait for the update to be complete before retrieving data2,
so that I will have the updated values in the data2 object?
The thing I see many people don't comprehend is the fact that using the TAP with async-await will infect your code like a plague.
What do I mean by that?
Using the TAP will cause async to bubble up all the way to the top of your call stack, that is why they say async method go "all the way". That is the recommendation for using the pattern. Usually, that means that if you want to introduce an asynchronous API, you'll have to provide it along side a separate synchronous API. Most people try to mix and match between the two, but that causes a whole lot of trouble (and many SO questions).
In order to make things work properly, you'll have to turn UpdateDataSet and GetMyDataSetById to be async as well. The outcome should look like this:
private readonly HttpClient httpClient = new HttpClient();
private async Task<string> GetDataSetAsync(string request)
{
httpClient.BaseAddress = theBaseAddress;
HttpResponseMessage response = await httpClient.GetAsync(request);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
private async Task PostDataSetAsync<T>(string request, T data)
{
client.BaseAddress = new Uri(theBaseAddress);
HttpResponseMessage response = await client.PostAsJsonAsync<T>(request, data);
response.EnsureSuccessStatusCode();
}
internal async Task<MyDataSet> GetMyDataSetByIdAsync(int id)
{
string request = String.Format("api/MyDataSet/GetById/{0}", id);
return JsonConvert.DeserializeObject<MyDataSet>(await GetDataSetAsync(request));
}
internal Task UpdateDataSetAsync(MyDataSet data)
{
return PostDataSetAsync("api/MyDataSet/Update", data);
}
Note - HttpClient is meant to be reused instead of a disposable, single call object. I would encapsulate as a class level field and reuse it.
If you want to expose a synchronous API, do so using a HTTP library that exposes a synchronous API, such as WebClient.
Always wait on the tasks right before you need its results.
Its always better to wait on a task if it contains an await in its body.
Warning : Do not use .Wait() or .Result
You would understand the concept better if you go through the control flow as explained Control Flow in Async Programs.
So in your case I would make all the functions accessing the async methods GetDataSet(string request) and PostDataSet<T>(string request, T data) with return type Task as awaitable.
Since you dont seem to expect any result back from the PostDataSet function you could just wait for it to complete.
PostDataSet("api/MyDataSet/Update", data).Wait();
I know it has been asked a lot, but my problem is, that my method won't wait for the request to be completet, even though i have implemented a TaskCompletionSource, which should have done the job, but it doesn't.
public DecksViewModel(bool local)
{
DList = new List<Deck>();
if (local)
InitializeLocalDeckList();
else
{
Dereffering();
}
}
public async void Dereffering()
{
var e = await InitilaizeWebDeckList();
List<DeckIn> decksIn = JsonConvert.DeserializeObject<List<DeckIn>>(e);
foreach (DeckIn d in decksIn)
{
Deck dadd = new Deck();
dadd.CardCount = 0;
dadd.Name = d.name;
dadd.PicturePath = d.image;
dadd.InstallDirectory = false;
DList.Add(dadd);
}
DataSource = AlphaKeyGroup<Deck>.CreateGroups(DList, System.Threading.Thread.CurrentThread.CurrentUICulture, (Deck s) => { return s.Name; }, true);
}
public Task<String> InitilaizeWebDeckList()
{
var tcs = new TaskCompletionSource<string>();
var client = new RestClient("blabla.com");
var request = new RestRequest("");
request.AddHeader("Authorization", "Basic blabla");
client.ExecuteAsync(request, response =>
{
test = response.Content;
tcs.SetResult(response.Content);
});
return tcs.Task;
}
So when I call the DecksViewModel constructor, I asyncally try to request the data from a webserver and fill the model.
The point is, that the corresponding view "doesn't wait" for the request to fill the model, so it's displayed empty.
I use the
List<AlphaKeyGroup<Deck>> DataSource
to fill a LongListSelector via DataBinding. But DataSource isn't yet set, when it is binded.
I hope you can help
You're calling an async method without awaiting it inside the constructor. That's why "it doesn't wait" (because it has nothing to wait on).
It's usually a bad idea to call an async method inside the constructor for that reason combined with the fact that constructors can't be async.
You should redesign your solution accordingly. An option is to have an async static method that creates an instance and awaits the procedure:
public static async Task CreateInstance(bool local)
{
var model = new DecksViewModel();
if (local)
{
await InitializeLocalDeckList();
}
else
{
await Dereffering();
}
}
That would allow you to not use async void which should only be used in UI even handlers.
You can read more about other options in Stephen Cleary's blog
You are using async void, which means nobody's gonna wait for that. It's just fire and forget.
I see some misunderstanding in the async keyword here:
Your code will only wait for the result of an async method, if you use await. Otherwise that call will just start the async method, but you don't know when it is actually gonna run.
You cannot use await in constructors though.