Given an operation such as this:
public void DoSomething()
{
IWcfServiceAgentAsync agent = new WcfServiceAgentProxy();
var request = new DoSomethingRequest();
agent.BeginDoSomething(request,
iar =>
{
var response = agent.EndDoSomething(iar);
/*
* Marshal back on to UI thread with results
*/
}, null);
}
What is really going on underneath the hood between the moment that the operation gets started, and the callback is executed? Is there a socket that's getting polled waiting for completion? Is there an underlying OS thread that gets blocked until it's return?
What happens is
BeginDoSomething
ends up callingbase.Channel.BeginGetTest(callback, asyncState);
on the WCF proxy. What that proxy then does is go through each part of the "Binding Stack" you have set up for your WCF communication.One of the main parts of the binding stack your request will pass through is the "Message Encoder". The message encoder packages your request up in to something that can be represented as a
byte[]
(This process is called Serializing).Once through the message encoder your request will be sent to the Transport (be it HTTP, TCP, or something else). The transport takes the
byte[]
and sends it to your target endpoint, it then tells the OS "When you receive a response directed to me, call this function" via the IO Completion Ports system. (I will assume either TCP or HTTP binding for the rest of this answer) (EDIT: Note, IO Completion ports don't have to be used, it is up to the Transport layer to decide what to do, it is just most of the implementations built in to the framework will use that)In the time between your message was sent and the response was received no threads, no poling, no nothing happens. When the network card receives a response it raises a interrupt telling the OS it has new information, that interrupt is processed and eventually the OS sees that it is a few bytes of data intended for your application. The OS then tells your application to start up a IOCP thread pool thread and passes it the few bytes of data that was received.
(See "There is no Thread" by Stephen Cleary for more info about this processes. It is talking about TPM instead of APM like in your example but the underlying layers are exactly the same.)
When the bytes from the other computer are received those bytes go back up the stack in the opposite direction. The IOCP thread runs a function from the Transport, it takes the bytes that was passed to it and hands it off to the Message Encoder. This action can happen several times!
The message encoder receives the bytes from the transport and tries to build up a message, if not enough bytes have been received yet it just queues them and waits for the next set of bytes to be passed in. Once it has enough bytes to desearalize the message it will create a new "Response" object and set it as the result of the
IAsyncResult
, then (I am not sure who, it may be the WCF call stack, it may be somewhere else in .NET) sees that yourIAsyncResult
had a callback delegate and starts up another IOCP thread and that thread is the thread your delegate is run on.