WCF and Proxies - WCF Architecture
(Page 3 of 6 )
So far in this chapter, I’ve covered all that is required to set up and consume simple WCF services. However, as described in the rest of the book, WCF offers immensely valuable support for reliability, transactions, concurrency management, security, and instance activation, all of which rely on the WCF interception-based architecture.
Having the client interact with a proxy means that WCF is always present between the service and the client, intercepting the call and performing pre-and post-call processing. The interception starts when the proxy serializes the call stack frame to a message and sends the message down a chain of channels. The channelis merely an interceptor, whose purpose is to perform a specific task. Each client-side channel does pre-call processing of the message. The exact structure and composition of the chain depends mostly on the binding. For example, one of the channels may be responsible for encoding the message (binary, text, or MTOM), another for passing security call context, another for propagating the client transaction, another for managing the reliable session, another for encrypting the message body (if so configured), and so on. The last channel on the client side is the transport channel, which sends the message over the configured transport to the host.
On the host side, the message goes through a chain of channels as well, which perform host-side pre-call processing of the message. The first channel on the host side is the transport channel, which receives the message from the transport. Subsequent channels perform various tasks, such as decryption of the message body, decoding of the message, joining the propagated transaction, setting the security principal, managing the session, and activating the service instance. The last channel on the host side passes the message to the dispatcher. The dispatcher converts the message to a stack frame and calls the service instance. This sequence is depicted in Figure 1-11.

Figure 1-11. The WCF architecture
The service has no way of knowing it was not called by a local client. In fact, it wascalled by a local client—the dispatcher. The interception both on the client and the service side ensures that the client and the service get the runtime environment they require to operate properly. The service instance executes the call and returns control to the dispatcher, which then converts the returned values and error information (if any) to a return message. The process is now reversed: the dispatcher passes the message through the host-side channels to perform post-call processing, such as managing the transaction, deactivating the instance, encoding the reply, encrypting it, and so on. The returned message goes to the transport channel, which sends it to the client-side channels for client-side post-call processing, which consists of tasks such as decryption, decoding, committing or aborting the transaction, and so on. The last channel passes the message to the proxy. The proxy converts the returned message to a stack frame and returns control to the client.
Most noteworthy is that almost all the points in the architecture provide hooks for extensibility—you can provide custom channels for proprietary interaction, custom behaviors for instance management, custom security behavior, and so on. In fact, the standard facilities that WCF offers are all implemented using the same extensibility model. You will see many examples and uses for extensibility throughout this book.
Host Architecture
It is also interesting to explore how the transition is made from a technology-neutral, service-oriented interaction to CLR interfaces and classes. The bridging is done via the host. Each .NET host process can have many app domains. Each app domain can have zero or more service host instances. However, each service host instance is dedicated to a particular service type. When you create a host instance, you are in effect registering that service host instance with all the endpoints for that type on the host machine that correspond to its base addresses. Each service host instance has zero or more contexts. The context is the innermost execution scope of the service instance. A context is associated with at most one service instance, meaning it could also be empty, without any service instance. This architecture is shown in Figure 1-12.

Figure 1-12. The WCF host architecture
The WCF context is conceptually similar to the Enterprise Services context or the .NET context-bound object context.
It is the combined work of the service host and the context that exposes a native CLR type as a service. After the message is passed through the channels, the host maps that message to a new or existing context (and the object instance inside) and lets it process the call.
Working with Channels
You can use channels directly to invoke operations on the service without ever resorting to using a proxy class. The ChannelFactory<T> class (and its supporting types), shown in Example 1-21, enables you to create a proxy on the fly.
Example 1-21. TheChannelFactory<T> class
public class ContractDescription
{
public Type ContractType
{get;set;}
//More members
}
public class ServiceEndpoint
{
public ServiceEndpoint(ContractDescription contract,Binding binding,
EndpointAddress address);
public EndpointAddress Address
{get;set;}
public Binding Binding
{get;set;}
public ContractDescription Contract
{get;}
//More members
}
public abstract class ChannelFactory : ...
{
public ServiceEndpoint Endpoint
{get;}
//More members
}
public class ChannelFactory<T> : ChannelFactory,...
{
public ChannelFactory(ServiceEndpoint endpoint);
public ChannelFactory(string configurationName);
public ChannelFactory(Binding binding,EndpointAddress endpointAddress);
public static T CreateChannel(Binding binding,EndpointAddress endpointAddress);
public T CreateChannel();
//More Members
}
You need to provide the constructor ofChannelFactory<T>with the endpoint—either the endpoint name from the client config file, or the binding and address objects, or aServiceEndpointobject. Next, use theCreateChannel()method to obtain a reference to the proxy and use its methods. Finally, close the proxy by either casting it toIDisposableand calling theDispose()method or toICommunicationObjectand calling theClose()method:
ChannelFactory<IMyContract> factory = new ChannelFactory<IMyContract>();
IMyContract proxy1 = factory.CreateChannel();
using(proxy1 as IDisposable)
{
proxy1.MyMethod();
}
IMyContract proxy2 = factory.CreateChannel();
proxy2.MyMethod();
ICommunicationObject channel = proxy2 as ICommunicationObject;
Debug.Assert(channel != null);
channel.Close();
You can also use the shorthand staticCreateChannel()method to create a proxy given a binding and an address, without directly constructing an instance ofChannelFactory<T>:
Binding binding = new NetTcpBinding();
EndpointAddress address = new EndpointAddress("net.tcp://localhost:8000");
IMyContract proxy = ChannelFactory<IMyContract>.CreateChannel(binding,address);
using(proxy as IDisposable)
{
proxy1.MyMethod();
}
Next: The InProcFactory Class >>
More Windows Scripting Articles
More By O'Reilly Media
|
This article is excerpted from chapter one of Programming WCF Services, written by Juval Lowry (O'Reilly, 2007; ISBN: 0596526997). Check it out today at your favorite bookstore. Buy this book now.
|
|