There are three types of ‘asynchronous’ things in Indigo:
- Async on the client. The client thread that starts a long-running operation returns immediately. The operation completes in the background and the client's application code is notifed of completion via a callback.
- Async on the server. The server thread that receives the request starts a long-running application operation and returns immediately to the thread pool. The application code calls back into Indigo when the operation completes, and then Indigo sends the response message.
- Async on the wire. Two servers communicating via a correlated series of one-way messages. Each side is free to send messages whenever it wants, and doesn't have to wait for a response to be recieved before sending another messages. These messages might be sent over the same connection, or different connections.
It’s important to note that (1) and (2) are simply implementation details of the local programming model and have nothing whatsoever to do with what goes out on the wire. For example, you can use an asynchronous programming model to talk to a server contract that is ‘synchronous’ (i.e. request/response) on the wire and everything will still work swimmingly. Only (3) — what we generally refer to in Indigo world as ‘duplex contracts’ — has an effect on the wire-level message exchange pattern.
From an implementation perspective, the following two service contracts are equivalent (they both define a single request/response operation “Echo” and generate the same WSDL):
ServiceContract( Name="Echo" )][
public interface ISyncEcho
{
[OperationContract( Action="Echo" )]
string Echo( string message );
}
[
ServiceContract( Name="Echo" )]public interface IAsyncEcho
{
[OperationContract( Action="Echo", AsyncPattern=true )]
IAsyncResult BeginEcho( string message, AsyncCallback callback, object state );
string EndEcho( IAsyncResult result );
}
You can use the sync version on one side and the async version on the other side with no ill effects — remember that the CLR interfaces used to describe service contracts are local abstractions and they do not have to be identical on both sides (only compatible). Svcutil /async will generate asynchronous signatures for you, or you can write them yourself given a synchronous signature. The conversion is pattern-based:
[OperationContract( Action=”Foo” )]
returnType Foo( parameterList );
becomes
[OperationContact( Action=”Foo”, AsyncPattern=true )]
IAsyncResult BeginFoo( parameterList, AsyncCallback callback, object state );
returnType EndFoo( IAsyncResult result );
Here's some code that demonstrates how you can mix-and-match sync and async programming models: AsyncSamples.zip (39kb)
