I think you're on the right path with async / await.
async tells the compiler that you are going to wrap everything in that method ContinueWith AFTER you reach the await keyword.
public void Something()
{
var task = new Task(() => DoWork());
task.ContinueWith(() => MoreWorkAfter());
task.Start();
}
//Is the same as
public async void Something()
{
var task = new Task(() => DoWork());
task.Start();
await Task;
MoreWorkAfter();
}
//Is also the same as
public async void Something()
{
var task = Task.Run(() => DoWork());
await Task;
MoreWorkAfter();
}
//Still the same as
public async void Something()
{
await Task.Run(() => DoWork());
MoreWorkAfter();
}
To make the method itself awaitable it has to return a Task object also because Task has the GetAwaiter() the await is looking for. Just remember that if you don't START the task it will await forever. So here's the same method written in an awaitable way for others.
public Task SomethingAsync()
{
return Task.Run(() => DoWork());
}
//Same as...
public async Task SomethingAsync()
{
await Task.Run(() => DoWork());
}
//And now in other methods you can....
public async void AnotherMethod()
{
await SomethingAsync();
//Do more work after it's complete.
}
Something to take away is that the Task is running on a new thread once it's started and to answer your question, yes it offloads the work. So for your original method keep it the same. The async method can Task.Run it like you've done.
public string MyComplexMethod(params)
{
//Access db
//Make WebRequests
//...
}
public async Task MyComplexMethodAsync(params)
{
await Task.Run(() => MyComplexMethod()).ConfigureAwait(false);
}
Something to note however; is that although you may call:
await MyComplexMethodAsync(params);
You have ConfigureAwait(false);
Which means any code after the task, in that method, will not be on the current context.
public async Task MyComplexMethodAsync(params)
{
//Main thread work here
await Task.Run(() => MyComplexMethod()).ConfigureAwait(false);//Background work here
//This will also be background work since CongfigureAwait(false);
}
public async Task MyComplexMethodAsync(params)
{
//Main thread work here
await Task.Run(() => MyComplexMethod()); //Background work here
//Main thread work here again since CongfigureAwait defaults to true;
}
And I say Main thread work but that assumes the Main thread called MyComplexMethodAsync.
The easiest way to grasp it is just imagine everything AFTER the await keyword is basically a new Action that gets called when the task is complete; just like using ContinueWith.
AND if there is code AFTER the await keyword in your method, it will BE SCHEDULED to run on the Main thread (considering the Main thread called the method to start with). Meaning it's a little like using Dispatcher.BeginInvoke if you've ever use it. The remaining portion get's queued to run on the Main thread in better terms. (Again, unless you put ConfigureAwait(false) and then it doesn't)