WCF Gross Anatomy from the Outside


Even though WCF is a very complex platform, it appears remarkably simple to the casual observer. As you saw in our Hello WCF examples, building a receiving application with WCF can be as simple as using an address, a binding, and a contract to build one or more endpoints. Building a sending application can be as simple as using a binding, a contract, and an address to send a message to that receiving endpoint. If, however, we want to modify local processing on the sender or the receiver, we are free to do so by either creating our own behaviors or using the behaviors that ship with WCF (like adding metadata support). Figure 4-1 shows the relationship between endpoints, addresses, bindings, contracts, and behaviors.

image from book
Figure 4-1: Endpoints, addresses, bindings, contracts, and behaviors

The Address

All applications that send or receive messages must make use of an address at some point in time. For example, receiving applications listen for incoming messages at some address, whereas sending applications direct messages to some target address. The WCF receiving infrastructure relies on the System.Uri type to build the receiving endpoint. The WCF sending infrastructure, on the other hand, relies on the System.ServiceModel.EndpointAddress type for directing messages to an ultimate receiver. An EndpointAddress type is the CLR abstraction of a WS-Addressing endpoint reference, and senders use this type to both add endpoint reference information to outbound messages and make the transport-level connection to the receiving endpoint (if there is one). Chapter 5 covers, among other things, the EndpointAddress type in detail.

In the context of WCF, an address is, in some form or fashion, a URI (an EndpointAddress object wraps a System.Uri object). One vital part of a URI is the scheme name. A scheme is an abstraction of the type of identifier that the URI represents, and the scheme name is a way to identify that scheme. In many cases, the scheme name matches the protocol that can be used to locate the resource, thereby using a URI as a URL. For example, the URI http://localhost:5000/IHelloWCF identifies http as the scheme name, and it just so happens that http (Hypertext Transfer Protocol) is also a transport. Internally, the WCF infrastructure must be able to use the URI to build either the sending or the listening infrastructure.

The Binding

Bindings are the primary way we express how a messaging application processes, sends, and receives messages. More specifically, it is the primary way we express the transport, WS-* protocols, security requirements, and transactional requirements an endpoint uses. WCF ships with nine bindings that cover a wide spectrum of transports, WS-* protocols, security requirements, and transactional requirements. If the capabilities do not fit the requirements of our application, we can define a custom binding that fits our particular needs.

In general, a binding is a type that defines much of our messaging infrastructure; it is a layer of abstraction around the transport and protocols that our application supports. To the developer, this abstraction means that the code required to send a message over the TCP/IP transport looks very similar to code that sends a message over MSMQ, thereby loosely coupling our application to a particular transport or set of protocols. Loose coupling in this manner means that application developers will be able to develop, adapt, and customize an application to fit customer demands more quickly than before.

All bindings subclass the System.ServiceModel.Channels.Binding type, and as a result, all bindings share common characteristics. One common characteristic of all bindings is that they maintain a private list of System.ServiceModel.Channels.BindingElement objects. A BindingElement is an abstraction of a particular facet of message exchange, like a transport or a WS-* protocol. All bindings expose a method named CreateBindingElements that builds and returns the list of binding elements for that particular binding. Shown here is a simple application that iterates over the nine default bindings in WCF and shows their BindingElement lists:

 using System; using System.ServiceModel; using System.ServiceModel.Channels; using System.Reflection; using System.Collections.Generic; using System.ServiceModel.MsmqIntegration; sealed class BindingElementsShow {   static void Main(){     List<Binding> bindings = new List<Binding>();     bindings.Add(new BasicHttpBinding());     bindings.Add(new NetNamedPipeBinding());     bindings.Add(new NetTcpBinding());     bindings.Add(new WSDualHttpBinding());     bindings.Add(new WSHttpBinding());     bindings.Add(new NetMsmqBinding());     bindings.Add(new MsmqIntegrationBinding());     bindings.Add(new WSFederationHttpBinding());     // throws if Peer Networking not installed     bindings.Add(new NetPeerTcpBinding());     ShowBindingElements(bindings);   }   private static void ShowBindingElements(List<Binding> bindings){     foreach (Binding binding in bindings){       Console.WriteLine("Showing Binding Elements for {0}",         binding.GetType().Name);       foreach (BindingElement element in binding.CreateBindingElements()){         Console.WriteLine("\t{0}", element.GetType().Name);       }     }  } }

This program generates the following output:

 Showing Binding Elements for BasicHttpBinding         TextMessageEncodingBindingElement         HttpTransportBindingElement Showing Binding Elements for NetNamedPipeBinding         TransactionFlowBindingElement         BinaryMessageEncodingBindingElement         WindowsStreamSecurityBindingElement         NamedPipeTransportBindingElement Showing Binding Elements for NetTcpBinding         TransactionFlowBindingElement         BinaryMessageEncodingBindingElement         WindowsStreamSecurityBindingElement         TcpTransportBindingElement Showing Binding Elements for WSDualHttpBinding         TransactionFlowBindingElement         ReliableSessionBindingElement         SymmetricSecurityBindingElement         CompositeDuplexBindingElement         OneWayBindingElement         TextMessageEncodingBindingElement         HttpTransportBindingElement Showing Binding Elements for WSHttpBinding         TransactionFlowBindingElement         SymmetricSecurityBindingElement         TextMessageEncodingBindingElement         HttpTransportBindingElement Showing Binding Elements for NetMsmqBinding         BinaryMessageEncodingBindingElement         MsmqTransportBindingElement Showing Binding Elements for MsmqIntegrationBinding         MsmqIntegrationBindingElement Showing Binding Elements for WSFederationHttpBinding         TransactionFlowBindingElement         SymmetricSecurityBindingElement         TextMessageEncodingBindingElement         HttpTransportBindingElement Showing Binding Elements for NetPeerTcpBinding         PnrpPeerResolverBindingElement         BinaryMessageEncodingBindingElement         PeerTransportBindingElement

As this output illustrates,the object returned from the CreateBindingElements method on a Binding is an ordered list of BindingElements. Notice that the last entry in the BindingElement list is always a transport BindingElement and that each BindingElement list contains a BindingElement that represents the message encoding. Several of the default bindings create BindingElement lists that contain additional BindingElements, but the transport BindingElements must always appear in this list.

In our output, you can also see that each Binding-derived type represents a set of messaging characteristics. At run time,the contents of the BindingElement list determine the messaging characteristics of an endpoint in our application. In other words, the Binding we choose for our endpoint has a direct impact on the way our application sends and receives messages. As a result, understanding the messaging characteristics of a particular Binding is vital to a successful WCF implementation. Table 4-1 shows the important characteristics of each binding that ships with WCF.

Table 4-1: Default Binding characteristics
Open table as spreadsheet
 

Interop

Security

Session

Transactions

Duplex

Streaming

Encoder

BasicHttpBinding

BP 1.1

T

   

image from book

TX

WSHttpBinding

WS-*

M

image from book

image from book

image from book

image from book

TX/MT

WSDualHttpBinding

WS-*

TM

image from book

image from book

image from book

 

TX/MT

NetTcpBinding

WCF

TM

image from book

image from book

image from book

image from book

B

NetMsmqBInding

WCF

TM

image from book

image from book

  

B

MsmqIntegrationBinding

MSMQ

T

    

TX

NetNamedPipeBinding

WCF

TM

image from book

image from book

image from book

image from book

B

NetPeerTcpBinding

WCF

T

    

B

WSFederationHttpBinding

WS-*

M

image from book

   

TX

BP 1.1 = Basic Profile 1.1, T = Transport, M =Message, TX = Text, MT = MTOM, B = Binary

When one first approaches the default WCF bindings, it is easy to become confused by the on a binding,you are really deciding on a binding for a particular endpoint, and an applicaspectrum of messaging options that these bindings provide. Keep in mind that when deciding tion can host multiple endpoints. If we build and deploy a receiving application that receives text-encoded messages over HTTP, we can easily add another endpoint so that the application also receives binary-encoded messages over TCP. For the most part, the Binding implemented at an endpoint is the primary means we use to express the messaging infrastructure of an endpoint. Chapter 8 describes bindings in detail.

The Contract

Contracts map object-oriented constructs to messaging constructs. More specifically, contracts define the endpoints in a receiving application, the MEP used by those endpoints, and the structure of the messages that an endpoint processes. For example, a contract helps to map the schema of a message body to a .NET Framework type definition, thereby simplifying the code required to generate a message whose contents match that schema. Three types of contracts are possible in WCF: service contracts, data contracts, and message contracts. Service contracts describe the operations in an endpoint. This description includes the name, the MEP, session-specific information, the action header block of both the request and the reply messages, and security information for each operation. Data contracts, on the other hand, map the structure of the body of a message to one or more operations. Message contracts map the structure of both the body and the header blocks of a message to one or more operations.

Note 

All contracts are annotated type and type member definitions, and the attribute used in the annotation controls whether the type definition represents a service, data, or message contract. It is important to remember that annotating a type or member definition simply adds information to the metadata of that type definition. As a result, all attribute definitions are inert. Performing work as a result of the presence of a specific attribute requires other code to interrogate the metadata of the type definition via the Reflection API. In the case of WCF contracts, the WCF infrastructure interrogates the metadata of a contract definition and takes action based on the contents of that metadata. It is possible to perform similar work manually, so contracts are optional. Practically speaking, the WCF infrastructure performs quite a bit of tedious work based on contract defintions, so virtually all the WCF applications you write should use contracts. I cover contracts in detail in Chapter 9.

Constructing a contract by annotating a type definition is inherently late-bound. Although this is one of the primary means by which WCF provides extensibility and adaptability for the developer, it also means that inconsistencies or incompatibilities might not be caught until run time.

Service Contracts

Service contracts represent the operations exposed by an endpoint and are used by both the sender and the receiver in a message exchange. Receiving applications can use a service contract to build the messaging infrastructure that listens for incoming messages. A sending application can use a service contract to build the messaging infrastructure that sends messages to a receiving endpoint. The information contained in a service contract includes the name of each operation, the parameters in that operation, the action header block associated with that operation, and session-specific information about that operation.

At the elemental level, a service contract is a class or an interface definition annotated with the ServiceContractAttribute attribute and one or more OperationContractAttribute attributes. The ServiceContractAttribute attribute is legal on both classes and interfaces, whereas the OperationContractAttribute is legal on methods. Most methods annotated with the OperationContractAttribute are members of a type annotated with the ServiceContractAttribute, with the one notable exception being duplex service contracts. Once again, I will cover this topic in detail in Chapter 9.

Data Contracts

Data contracts map .NET Framework types to the body of a message. If SOAP is the chosen messaging structure, a data contract maps a .NET Framework type to the schema of a SOAP message body. Like any WCF contract, a data contract is an annotated type definition, and the operative attributes are the DataContractAttribute and the DataMemberAttribute. Most of the time, a service contract references a data contract, as shown in the following example:

 [ServiceContract] interface ISomeServiceContract {   [OperationContract]   void SomeOperation(SomeDataContract info); // notice the argument type } [DataContract()] sealed class SomeDataContract {   [DataMember]   Int32? number;   String status;   [DataMember] // must have getter and setter   internal String Status {     get { return status; }     set { status = value; }   }   internal Int32? Number {     get { return number; }   }   internal SomeDataContract(Int32? number) : this(number, null)   {   }   internal SomeDataContract(Int32? number, String status) {     this.number = number;     this.status = status; // consider the null case   } }

In this example, the ISomeServiceContract interface defines a method that accepts an argument of type SomeDataContract. Since the SomeDataContract type is annotated with the DataContractAttribute, the body of the message sent to the SomeOperation operation will have a schema dictated by the SomeDataContract type.

Message Contracts

Message contracts map .NET Framework types to the structure of a message. If XML is the messaging structure, a message contract maps a .NET Framework type to the schema of the message. This includes both the header blocks and body of a message, as shown here:

 [ServiceContract] interface ISomeServiceContract {   [OperationContract]   void SomeOperation(SomeDataContract info); // notice the argument type   [OperationContract]   void SomeOtherOperation(SomeMessageContract info); // notice the argument type } [DataContract()] sealed class SomeDataContract {   [DataMember]   Int32? number;   String status;   [DataMember] // must have getter and setter   internal String Status {     get { return status; }     set { status = value; }   }   internal Int32? Number {     get { return number; }   }   internal SomeDataContract(Int32 number) : this(number, null)   {   }   internal SomeDataContract(Int32 number, String status) {     this.number = number;     this.status = status; // consider the null case   } } [MessageContract] sealed class SomeMessageContract {     SomeMessageContract() {  }  // must have default constructor     [MessageHeader]     Int32? SomeNumber;     [MessageBodyMember]     SomeDataContract messageBody;     internal SomeMessageContract(Int32? someNumber) {         SomeNumber = someNumber;         messageBody = new SomeDataContract(someNumber);     } }

Notice from the preceding code snippet that the SomeOtherOperation method on the ISomeServiceContract interface accepts an argument of type SomeMessageContract. This is legal because the SomeMessageContract type definition has the MessageContractAttribute annotation. There is quite a bit of information to cover in contracts, and we’ll do the topic justice in Chapter 9.




Inside Windows Communication Foundation
Inside Windows Communication Foundation (Pro Developer)
ISBN: 0735623066
EAN: 2147483647
Year: 2007
Pages: 106
Authors: Justin Smith

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net