Reputation: 1892
I have a WCF operation Say Service1.OperationA. This operation has to call another Operartion Service2.OprationB. OperationB is called as last step in OperationA. OperationB returns just true or false.
Operation B does some read and writes to database and it might take long time. When Calling this method from operation B, I do not want to wait for the result of OperationB. Even if throws exception I will catch and log the exception. There are other operations like OperationC which might want to wait for the result of OperationB.
Upvotes: 1
Views: 852
Reputation: 30454
The most easy method is to use async-await.
<TResult
>In your async function just call the other async function. If you need the result immediately use await, if you have something else to do, do this while the async function is performing and await for the Task when you need the result.
Let's suppose your slow OperationB downloads the complete Shakespeare. As an async function this would be like:
private async Task<string> OparationBAsync()
{ // read Shakespeare sonnets:
string uri = "http://www.gutenberg.org/cache/epub/1041/pg1041.txt";
using (var webClient = new WebClient())
{
return await webClient.DownloadStringTaskAsync(uri);
}
}
If OperationA is async and you want to wait for the result of OperationB, await for the result:
private async Task OperationAAsync(...)
{
Task<string> taskReadBook = OperationB();
// while reading do some other useful stuff
// when you need the result: await for the task:
string book = await taskReadBook;
ProcessBook (book);
}
Of course, if you don't need the result, don't await for it. Call the other async function and return whenever you are ready. You'll probably get a compiler warning that you don't await, but wasn't that what you wanted?
<TResult
>.
private async void Button1_Clicked(object sender, ...)
{
OperationA();
// use the synchronous version or
// use the async version and wait until finished:
await OperationAAsync();
OperationBAsync();
// do not await until finished.
}
The problem is, if you want to do something with the result, no one will know that OperationBAsync is finished. Suppose you have an operationCAsync that writes the read data:
private async Task OperationCAsync(string filename, string text)
{
using (var textWriter = new StreamWriter(fileName))
{
await WriteAsync(text);
}
}
The easiest method would be that the calling functions would wait:
private async void Button1_Clicked(object sender, ...)
{
await OperationAAsync();
var book = await OperationBAsync();
await OperationC("mybook.txt", book);
}
Even though you don't start a task explicitly, the async makes that your UI keeps responsive during the times that the functions are awaiting. Be aware though that it still is the UI thread that does the processing, so while the code is not awaiting, your UI thread will be busy. If you really want to free the UI from this burden, you'll need to start a seperate thread:
private void Button1_Clicked(object sender, ...)
{ // not async version, the UI will not wait for the result
Task.Run( () => Button1ClickedHandler();
}
private async Task Button1ClickedHandler()
{
await OperationA();
var book = await OperationB();
await OperationC("mybook.txt", book);
}
Of course you'll have to take care that Button1ClickedHandler is not performed by the UI thread anymore, so it can't touch any UI item (buttons, graphs etc) You'll also have to think about what to do if the button is clicked while the action is still busy.
Finally a neat trick, you can start several tasks, and wait until all are finished:
private async Task StartSeveralTasks()
{
var taskA = OperationA(),
var taskB = OperationB(),
var taskC = OperationC(...),
};
await Task.WhenAll(new Task[] {taskA, taskB, taskC});
// because taskB is a Task<string>, taskB has a property Result:
string book = taskB.Result;
}
Task.WhenAll wraps all exceptions thrown by any of the tasks in an System.AggregateException. This class has a property InnerExceptions that contains the sequence of all occurred exceptions.
Upvotes: 2
Reputation: 1721
You can use Task.Run()
for doing OperationB in different thread. Like:
OperationA()
{
//some code
Task.Run(() => { OperationB(); });
//continue your code.
}
Upvotes: 0