I'm writing a networked application.
Messages are sent over the transport as such:
Network.SendMessage (new FirstMessage() );
I can register an event handler to be called when this message type arrives, like so:
Network.RegisterMessageHandler<FirstMessage> (OnFirstMessageReceived);
And the event gets fired:
public void OnFirstMessageReceived(EventArgs<FirstMessageEventArgs> e)
{
}
I'm writing a custom authentication procedure for my networked application, which requires around five messages to complete.
Without using the Task Parallel Library, I would be forced to code the next step of each procedure in the preceding event handler, like so:
public void OnFirstMessageReceived(EventArgs<FirstMessageEventArgs> e)
{
Network.SendMessage( new SecondMessage() );
}
public void OnSecondMessageReceived(EventArgs<SecondMessageEventArgs> e)
{
Network.SendMessage( new ThirdMessage() );
}
public void OnThirdMessageReceived(EventArgs<ThirdMessageEventArgs> e)
{
Network.SendMessage( new FourthMessage() );
}
public void OnFourthMessageReceived(EventArgs<FourthMessageEventArgs> e)
{
// Authentication is complete
}
I don't like the idea of jumping around the source code to code a portion of this and a portion of that. It's hard to understand and edit.
I hear the Task Parallel Library substantially simplifies this solution.
However, many of the examples I read using the Task Parallel Library were related to starting a chain of active tasks. What I mean by 'active', is that each task could start when called explicitly, like so:
public void Drink() {}
public void Eat() {}
public void Sleep() {}
Task.Factory.StartNew( () => Drink() )
.ContinueWith( () => Eat() )
.ContinueWith( () => Sleep() );
This is opposite from my event-based async pattern, in which each event handler method is called only when the message is received.
In other words, I can't do something like this (but I want to):
Task.Factory.StartNew( () => OnFirstMessageReceived() )
.ContinueWith( () => OnSecondMessageReceived() )
.ContinueWith( () => OnThirdMessageReceived() )
.ContinueWith( () => OnFourthMessageReceived() );
I've read this article, but I don't quite understand it. It seems like what I need has to do with TaskCompletionSource
. If I wanted to make a task from my event-based async pattern like the code block above, what would it look like?
Jeremy Likness has a blog entry title Coroutines for Asynchronous Sequential Workflows using Reactive Extensions (Rx) that might interest you. Here is the question he tries to answer:
You're right about TaskCompletionSource, it's the key to transforming EAP (event-based asynchronous pattern) to TPL's Task.
This is documented here: https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/tpl-and-traditional-async-programming#exposing-complex-eap-operations-as-tasks
Here is the simplified code:
Now, all you need to do, to make a chain of those operations, is just to set your continuations (which is not very comfortable at the moment, and the C# 5 await and async will help alot with it)
So, this code could be used like this: