Reputation: 380
I have a task that needs to call an http request to server and I do it like this:
public static async Task<BoundingBox> Transform(this BoundingBox boundingBox, string epsg) {
...
var min = _httpClient.GetStringAsync("https://epsg.io/trans?x=435951&y=5549182&s_srs=25832&t_srs=3857");
var max = _httpClient.GetStringAsync("https://epsg.io/trans?x=435911&y=5549122&s_srs=25832&t_srs=3857");
await Task.WhenAll(min, max);
...
}
priorityBb = bb.Transform("epsg:3857").GetAwaiter().GetResult();
But it makes my UI hang.
What is wrong with my code? Many thank for your comment.
Upvotes: 0
Views: 97
Reputation: 22038
You must await the Transform
method, because the task returned is probably not completed yet instead of GetAwaiter().GetResult()
. You'll probably never need to use these methods. GetResult()
will block the current thread while the task is not completed.
This is a rough sketch, I have too little information about your structure:
public class MyResults
{
public string Min {get;set;}
public string Max {get;set;}
}
public static async Task<MyResults> Transform(this BoundingBox boundingBox, string epsg) {
...
var minTask = _httpClient.GetStringAsync("https://epsg.io/trans?x=435951&y=5549182&s_srs=25832&t_srs=3857");
var maxTask = _httpClient.GetStringAsync("https://epsg.io/trans?x=435911&y=5549122&s_srs=25832&t_srs=3857");
await Task.WhenAll(minTask, maxTask);
// you can access the Results now, because all tasks are completed.
return new MyResults { Min = minTask.Result, Max = minTask.Result };
}
public static async Task GetMyData()
{
var myResults = await bb.Transform(".....");
// ^^^^^
Console.WriteLine(myResults.Min);
Console.WriteLine(myResults.Max);
}
If the caller isn't supporting async, you could try something like: (haven't tested it so, you'll have to check it)
The TaskScheduler.FromCurrentSynchronizationContext()
is only needed when you are dealing with (for example) a UI thread.
public static void GetMyData()
{
// You are not able to await it here. Fire and "forget"
Task.Run<MyResults>(() =>
{
// Not executed on the UI thread
return bb.Transform(".....");
})
.ContinueWith(transformTask =>
{
// back on the UI thread.....
var myResults = transformTask.Result;
Console.WriteLine(myResults.Min);
Console.WriteLine(myResults.Max);
}, TaskScheduler.FromCurrentSynchronizationContext());
}
Upvotes: 3
Reputation: 598
priorityBb = bb.Transform("epsg:3857").GetAwaiter().GetResult();
This line is blocking your UI thread, because of call to GetResult
. Earlier you used async
/await
correctly, but in this line you are mixing async code with blocking code. You should use same approach as in Transform
method and await
the result instead of blocking using GetResult
To fix this simply change that line to
priorityBb = await bb.Transform("epsg:3857");
Using GetResult
like that can lead to deadlocks and in most situations is not a good idea. Whenever you can just stick to async
/await
.
If you can't make your caller async
then your call can't be async
. async
/await
is probably best approach here but if for some reason you can't use it you can wait for response and handle it on another thread using Task.Run
Upvotes: 2