We have a collection we want to loop through which we need to make a service call for each item in the collection and await the response before executing the next service call in the collection.
The issue is that I am unable to await the response before executing the next item in the collection, I did manage to get this to work by triggering the result using TaskCompletionSource but this seems dirty. Is there a better way to do this?
I have tried using 'Func oftype Task' but couldn't seem to get this to work.
public async Task<bool> PerformRTV(string policyId)
{
if (!Instance.RTVDone)
{
var result = new TaskCompletionSource<bool>();
PerformValuation(policyId, resp =>
{
if (!(resp.Error is null))
{
ErrorService.LogError(resp.Error);
result.SetResult(false);
return;
}
if (!resp.Result)
{
result.SetResult(false);
return;
}
result.SetResult(true);
return;
});
return await result.Task;
}
else
{
return true;
}
}
private void PerformValuation(string policyId, Action<#########CompletedEventArgs> response)
{
Service.HookResponseHandlerToServiceEvent(_portfolioServiceClient, nameof(_portfolioServiceClient.#########Completed), response);
_portfolioServiceClient.#########RTVAsync(policyId, ApplicationSettings.Authentication.TPCodeID);
}
In a nutshell I am calling the PerformRTV in a loop and want to wait the response before calling PerformRTV with the next item in the loop.
No, TaskCompletionSource is not dirty. I think it's the way to go.
I would just return the Task itself, instead of await it in this method (not a async method). The decision of awaiting could be done a level up. You might want to await multiple calls. And for returning true directly, you could use the Task.FromResult()
Related
I understand how I can await on library code to wait for a network request or other long-running action to complete, but how can I await on my own long-running action without busy waiting?
This is the busy-waiting solution. How can I make it event-driven?
public async Task<DataBlock> ClickSend() {
// await until someone calls DataReceived()
while (_Block == null) {
await Task.Yield();
}
return _Block;
}
// Something external calls this function.
// Once called, ClickSend should complete with this data.
public void DataReceived(DataBlock data_block) {
_Block = data_block;
}
DataBlock _Block = null;
(This question is completely different from How do I await events in C#? which is asking how to await on event handlers, but very similar to Promise equivalent in C#.)
Generally in concurrency a "future" is placeholder for a return value and it has an associated "promise" that is fulfilled to pass the final return value.
In C#, they have different names: the future is a Task and the promise is a TaskCompletionSource.
You can create a promise, await on it, and then fulfill it when you get your callback:
TaskCompletionSource<DataBlock> _Promise = new TaskCompletionSource<DataBlock>();
public async Task<DataBlock> ClickSend() {
DataBlock block = await _Promise.Task;
return block;
}
public void DataReceived(DataBlock data_block) {
_Promise.TrySetResult(data_block);
}
Here's an executable example.
I am using Ninject 3.2.2.0 and I am trying to bind an async method.
This is what I got so far:
kernel.Bind<Task<MyInterface>>().ToMethod(async ctx =>
{
var someData = await DoSomethingAsync();
return new SomethingElse(someData);
}).InRequestScope();
My method DoSomethingAsync never gets called. I believe it's not being called because MyInterface is being requested, not Task<MyInterface>.
Any ideas?
The construction of your object graph should be reliable and fast. This excludes doing anything that is I/O related. This means that you should not do anything that is asynchronous at all.
Instead anything that is slow, unreliable or asynchronous should be postponed untill after the object graph is constructed.
I ended up making my binding sync
kernel.Bind<MyInterface>().ToMethod(ctx =>
{
var someData = DoSomethingSync(); // <-- Made this one sync, see method below
return new SomethingElse(someData);
}).InRequestScope();
Here is the 'magic'. I changed my method from:
private async Task<string> DoSomethingAsync() {
var result = await DoSomethingElseAsync();
return result;
}
To
private string DoSomethingSync() {
string result = null;
var runSync = Task.Factory.StartNew(async () => {
result = await DoSomethingElseAsync();
}).Unwrap();
runSync.Wait();
return result;
}
I know performance is affected because of the context switch, but at least it works as expected and you can be sure that it won't deadlock.
I have the following code:
var result = MessageBoxHelper.MsgBox
.ShowAsync("Press Yes to proceed", MessageBoxButton.YesNo)
.ContinueWith((answer) =>
{
if (answer.Result == MessageBoxResult.Yes)
{
Task<bool> asyncTask = ExecuteAsyncFunc();
//asyncTask.Unwrap(); ??
asyncTask.ContinueWith((a) =>
{
// More
}, TaskContinuationOptions.OnlyOnRanToCompletion);
}
}, TaskContinuationOptions.OnlyOnRanToCompletion);
}
Invoked elsewhere like this:
public async Task<bool> ExecuteAsyncFunc()
{
await CallAnotherAsyncFunction();
}
I believe that I need to call Unwrap(), where I have tried to, because I am calling await inside a ContinueWith() block. However, I get the following error when I uncomment it:
Error CS1929 'Task' does not contain a definition for 'Unwrap'
and the best extension method overload
'TaskExtensions.Unwrap(Task)' requires a receiver of type
'Task'
Do I need to use Unwrap in this context, and if so, what am I doing wrong?
The short answer is to use await instead of ContinueWith:
var result = MessageBoxHelper.MsgBox.ShowAsync("Press Yes to proceed", MessageBoxButton.YesNo);
if (answer == MessageBoxResult.Yes)
{
var a = await ExecuteAsyncFunc();
// More
}
The long answer is that ContinueWith has some dangerous default options (including using an ambient TaskScheduler), and await automatically does everything correctly for you. I go into more detail on my blog.
Do I need to use Unwrap in this context, and if so, what am I doing
wrong?
You need to Unwrap only when your return type is a Task<Task>, and you actually want to do something with the inner task.
For example:
Task<Task> exampleTask = Task.Factory.StartNew(async () =>
{
await Task.Delay(1000);
});
If I wanted to actually asynchronously wait on the inner Task, i'd call Unwrap and await on that:
Task exampleTask = await Task.Factory.StartNew(async () =>
{
await Task.Delay(1000);
}).Unwrap();
If for any reason you'd want to await on any task returned from your continuation, or want to monitor the inner task, then you'd call Unwrap. There is no need to do that here.
What you're doing is simply invoking an async method inside your ContinueWith, but it doesn't seem like you want to await the result at all.
I'd recommend using async-await wherever possible to reduce the verbosity of ContinueWith. Mixing those two together usually yields bad results as thing get rather complicated. Refactoring that code ends up much cleaner with much less cyclomatic complexity:
var result = await MessageBoxHelper.MsgBox.ShowAsync("Press Yes to proceed",
MessageBoxButton.YesNo);
if (result == MessageBoxResult.Yes)
{
bool answer = await ExecuteFuncAsync();
}
You say that you have to call unwrap due to your using await inside the ContinueWith; I don't actually see you using await though. I assume what you meant is that you want to await but are not sure how, and thus thought unwrapping is needed. If that is the case, then what you want is to just make your nested Task awaitable. You can do that by making the delegate you provide async
var result = MessageBoxHelper.MsgBox
.ShowAsync("Press Yes to proceed", MessageBoxButton.YesNo)
.ContinueWith(async (answer) =>
{
if (answer.Result == MessageBoxResult.Yes)
{
await ExecuteAsyncFunc();
}
}, TaskContinuationOptions.OnlyOnRanToCompletion);
public async Task<bool> ExecuteAsyncFunc()
{
await CallAnotherAsyncFunction();
}
This allows you to await within the delegate, within the ContinueWith call and not have to deal with unwrapping.
If you are going to do anything with the Task, such as return it without unwrapping, then this is the right way to go.
public Task<BoolOrSomeOtherReturnType> Foo()
{
return MessageBoxHelper.MsgBox
.ShowAsync /* Continue with etc here */
}
But if you are going to act on the results within the Foo method, then there is no need to use ContinueWith, just await it.
public async Task<bool> Foo()
{
var result = await MessageBoxHelper.MsgBox
.ShowAsync("Press Yes to proceed", MessageBoxButton.YesNo);
if (result == MessageBoxResult.Yes)
{
await ExecuteAsyncFunc();
return true;
}
return false;
}
That simplifies your code quiet a bit. The other thing to note is that your ExecuteAsyncFunc() method does not act on the return value. You simply await and do nothing else.
I noticed that you're not returning true/false, so I assume there is more code there that you just omitted for clarity sake. If that isn't the case, you can save yourself some overhead and just return the Task, allowing someone further up the callstack to await it instead. If your call to CallAnotherAsyncFunction returns Task<bool> then you can just return that call in the same way as well. You only need to await if you have to prevent the method from going any further so you can react to the result of the awaited method. If you don't have to, just return the Task.
public Task<bool> ExecuteAsyncFunc()
{
return CallAnotherAsyncFunction();
}
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.
I need to do a RestRequest and get some JSON, I am not sure if my method is really async since there is still a little freeze in my UI when I use this method.
public async Task<List<MyObject>> Load()
{
var tcs = new TaskCompletionSource<List<Myobject>>();
var client = new RestSharp.RestClient("https://exampleapi.com");
client.Authenticator = OAuth1Authenticator.ForProtectedResource(
[...]);
var request = new RestSharp.RestRequest("examp.json", Method.GET);
client.ExecuteAsync(request, response =>
{
if (response.StatusCode == HttpStatusCode.OK)
{
List_ = new List<MyObject>();
List_ = JsonConvert.DeserializeObject<List<MyObject>>(response.Content);
tcs.SetResult(List_);
}
else
{
MessageBox.Show("Error");
}
});
return await tcs.Task;
}
Specially for this line of code :
List_ = JsonConvert.DeserializeObject<List<MyObject>>(response.Content);
is it really async ? because it seems to block the the UI . Can you tell me how can I make this function properly async ?
It seems the delegate passed as an argument to ExecuteAsync is being executed on the UI thread. If that is the case, simply use Task.Run to run the delegate on the threadpool instead.
client.ExecuteAsync(request, async (response) =>
{
if (response.StatusCode == HttpStatusCode.OK)
{
var list = await Task.Run( () => JsonConvert.DeserializeObject<List<MyObject>>(response.Content));
tcs.SetResult(list);
}
else
{
MessageBox.Show("Error");
}
});
Is List_ a field? It seems to me like it should be a local variable. Also, there's no need to initialize it with an empty list before deserializing the json.
JsonConvert.DeserializeObject is synchronous. You can tell by the fact that it returns you the result of its computation immediately. There is no way it could do something "in the background" and only later hand you the result.
Move CPU bound work to a thread-pool thread using Task.Run. You can move the whole REST request there if that is more convenient to you.
Note, that your message box call should run on the UI thread. Better not create a message box on a thread-pool thread like you are doing at the moment. That will result in two UI threads. The message box will not be modal.