Export (0) Print
Expand All
5 out of 7 rated this helpful - Rate this topic

Introducing Windows Communication Foundation: Accessible Service-Oriented Architecture

This chapter is excerpted from Programming .NET 3.5: Build N-Tier Applications with WPF, AJAX, Silverlight, LINQ, WCF, and More by Jesse Liberty, Alex Horovitz, published by O'Reilly Media

There is a great deal of buzz around the concept of Service-Oriented Architecture (SOA), and with good reason. People engaged in the world of enterprise computing spend a great deal of time and energy getting systems to talk to one another and interoperate. In an ideal world, we would like to be able to connect systems arbitrarily, and without the need for proprietary software, in order to create an open, interoperable computing environment. SOA (often pronounced SO-ah) is a big step in the right direction.

SOA Defined

A Service-Oriented Architecture is based on four key abstractions:

  • An application frontend

  • A service

  • A service repository

  • A service bus

The application frontend is decoupled from the services. Each service has a "contract" that defines what it will do, and one or more interfaces to implement that contract.

The service repository provides a home for the services, and the service bus provides an industry-standard mechanism for connecting to and interacting with the services.

Because all the services are decoupled from one another and from the application frontend, SOA provides the desired level of interoperability in a nonproprietary open-systems environment.

Enterprise architects look at SOA (Figure 10.1, "SOA overview") as a means of helping businesses respond more quickly and cost-effectively to changing market conditions.

Figure 10.1. SOA overview

SOA overview

Windows Communication Foundation (WCF) provides a SOA technology that offers the ability to link resources with an eye on promoting reuse. Reuse is enabled at the macro (service) level rather than the micro (object) level. The SOA approach coupled with WCF also simplifies interconnection among (and usage of) existing IT assets.

Defining a Service More Precisely

It is important to be clear about what we mean when we use the word "service" in the SOA context. Typically we are thinking about a business service, such as making a hotel reservation or buying a computer online, but keep in mind that these services do not include a visible element. Services do not have a frontend-they expose either functionality or data with which other programs can interact through web browsers, desktop applications, or even other services.

These services might implement business functions like searchForAvailability or setShippingMethod. In this respect they are distinctly different from technical services, which might provide messaging or transactional functions such as updating data or monitoring transactions. By design, SOA deliberately decouples business services from technical services so that your implementation does not require a specific underlying infrastructure or system. In short, a SOA service is the encapsulation of a high-level business concept.

A SOA service is composed of three parts:

  • A service class that implements the service to be provided

  • A host environment to host the service

  • One or more endpoints to which clients will connect

All communication with a service happens through the endpoints. Each endpoint specifies a contract (which we will discuss in greater detail later in this chapter) that defines which methods of the service class will be accessible to the client through that specific endpoint.

Because the endpoints have their own contracts, they may expose different (and perhaps overlapping) sets of methods. Each endpoint also defines a binding that specifies how a client will communicate with the service and the address where the endpoint is hosted.

You can think of SOA services in terms of four basic tenets:

  • Boundaries are explicit.

  • Services are autonomous.

  • Schemas and contracts are shared, but not classes.

  • Compatibility is based on policy.

These fundamental tenets help drive the design of the services you'll create, so it's worth exploring each in detail.

Boundaries Are Explicit

If you want to get somewhere in the physical world, it is crucial to know where you are and where you need to go, as well as any considerations that need to be accounted for on your way (which is why GPS systems are one of the fastest-selling technologies in the consumer market).

This also applies to services. There will be boundaries between each interaction, and crossing these boundaries involves a cost for which you must account.

As a concrete example, when driving from Boston to Manhattan, you can take a faster toll route (that costs money) or a slower free route (that costs time). A similar tradeoff applies with service operations that cross process or machine boundaries. You face decisions about resource marshaling, physical location and network hops, security constraints, and so forth. Among the "best practices" for minimizing the cost of crossing these boundaries are the following considerations:

  • Make sure your entry-point interface is well defined, comprehensive, and public. This will encourage consumers to utilize your service as opposed to doing end runs around it.

  • Consumption is your primary reason for existence, so make that easy. Don't make the developers who consume your service think (with apologies to Steve Krug).

  • Be explicit! Use messages, not Remote Procedure Calls. The RPC model was an interim (crutch) analogy used by Microsoft for web services in earlier versions of .NET to smooth the transition; due to its synchronous implementation, the modern WCF style eschews RPC in the interest of building strong SOA decoupling through asynchronous messaging.

  • Hide implementation details to avoid tight coupling.

  • Keep it simple-send well-defined messages in both directions with as small an interface as possible to get the job done. To quote Albert Einstein (Figure 10.2, "Albert Einstein Sticking Out His Tongue ©Bettmann/CORBIS"), "As simple as possible, but not simpler."

Figure 10.2. Albert Einstein Sticking Out His Tongue ©Bettmann/CORBIS

Albert Einstein Sticking Out His Tongue ©Bettmann/CORBIS

Services Are Autonomous

SOA services are expected to run in the wild world of decoupled systems. A well-designed service should stand alone and be totally independent and relatively failsafe. As the service topology is almost guaranteed to evolve over time, and there is no presiding authority, you should plan to meet this goal through autonomous design.

Here are some points to keep in mind:

  • If Murphy ("Anything that can go wrong will go wrong") designed a service, he would do everything he could to isolate that service from all other services, to prevent dependencies and reduce the risk of failure.

  • Your service deployments and versions will be independent of the system on which they are deployed.

  • Keep your word-once you publish a contract, never change it!

  • There is no presiding authority, so plan accordingly.

Schemas and Contracts Are Shared, But Not Classes

As the creator of a service, it is your responsibility to provide a well-formed contract. Your service contract will contain the message formats, the message exchange patterns, BPEL scripts that might be required, and any WS-Policy requirements. After publication, stability becomes your biggest responsibility. Make no changes, and ensure that any changes you do make (paradox intentional) have a minimal impact on your consumers. Key considerations include:

  • Stability is job one! Don't publish a contract for others until you are sure the service is stable and not likely to change.

  • Say what you mean and mean what you say. Be explicit in your contracts to ensure that people understand both the explicit and intended usages.

  • Make sure the public data schema is abstract; don't expose internal representations.

  • If you break it, you version it. Even the best-designed service might need to change; use versioning to help insulate your consumers from these changes.

WS-Policy

WS-Policy provides a syntax and a general-purpose model to describe and communicate the policies of a web service. WS-Policy assertions express the capabilities and constraints of your particular web service. WS-PolicyAttachments tell your consumers which of the several methods for associating the WS-Policy expressions with web services (e.g., WSDL) your web service implements.

Compatibility Is Based on Policy

There may come a time when you will not be able to capture all the requirements of a service interaction via the Web Services Description Language (WSDL) alone. This is where policies come in. Policies allow you to separate the what from the how and the whom when it comes to a communicated message. If you have policy assertions, you need to make sure you are very explicit with respect to expectations and compatibility. Keep these points in mind:

  • Say what your service can do, not how it does it-separate interactions from constraints on these interactions.

  • Express capabilities in terms of policies.

  • Assertions should be identified by stable and unique names.

It is important to recognize that a web service is just one of many service implementations. That said, the increasing ease with which one can create a web service has been a catalyst for the explosion of SOA implementations in recent years. It is the basic nature of the web service, "a programmable application component accessible via standard web protocols," that is helping deliver on the promise of SOA. In a nutshell, you can think of SOA as having three components:

  • Standard protocols-HTTP, SMTP, FTP with HTTP

  • Service description-WSDL and XSD

  • Service discovery-UDDI and other "yellow pages"

The protocol stack for WCF's implementation of web services is outlined in Figure 10.3, "The web services protocol stack". Web services typically flow from top to bottom (discovery, then description, then messaging).

To consume a web service, you need to know that it exists, what it does, what kind of interface it offers, and so on. You should also note that with WCF, you are strongly encouraged to use UDDI for publishing your web service's metadata exchange endpoints, and to query the service directly for the WSDL document and policies. After all of this has been accomplished, your client can invoke the web service via SOAP.

We'll start at the bottom of the stack and work our way back up.

SOAP: More Than Just a Cleanser

SOAP is the preferred protocol for exchanging XML-based messages over computer networks using the standard transport mechanisms outlined in the preceding section. SOAP is the top end of the foundation layer of the web services stack. As such, it provides a basic messaging framework that is used to construct more abstract layers.

Figure 10.3. The web services protocol stack

The web services protocol stack
Tip
Trivia question: What does SOAP stand for?Old answer: Simple Object Access Protocol.New answer (by dictate of the World Wide Web Consortium as of June 2003): Nothing at all.

While there are several different types of messaging patterns in SOAP, up to this point the most common for .NET programmers has been the RPC pattern, in which one side of the messaging relationship is designated the server and one side the client. The client pretends to make a method call on the server through a proxy, and the server pretends to respond by running a method and returning a value (Figure 10.4, "Bare-bones, one-way SOAP communication"). What is actually happening, however, is that XML documents are being exchanged "under the covers," hidden by the framework so that the developer need not be exposed to the details of XML syntax.

Figure 10.4. Bare-bones, one-way SOAP communication

Bare-bones, one-way SOAP communication

Here is an example of how a client might format a SOAP message requesting product information from a computer seller's warehouse web service. The client needs to know which product corresponds with the ID MA450LL/A:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <getProductDetails xmlns="http://computer.seller.com/ws">
         <productID>MA450LL/A</productID>
      </getProductDetails>
   </soap:Body>
</soap:Envelope>

And here is a possible response to the client request:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <getProductDetailsResponse xmlns="http:// computer.seller.com/ws">
         <getProductDetailsResult>
            <productName>iPod </productName>
            <productID>MA450LL/A</productID>
            <description>iPod, 80GB - Black</description>
            <price currency="NIS">349.00</price>
            <inStock>true</inStock>
         </getProductDetailsResult>
      </getProductDetailsResponse>
   </soap:Body>
</soap:Envelope>

If you break down a SOAP message you'll see that it contains distinct parts, which are represented in Figure 10.5, "The structure of a SOAP message".

SOAP messages come in three flavors: requests, responses, and faults. The only required element of a SOAP message is the envelope, which encapsulates the message that is being communicated and specifies the protocol the message uses for communication. As you can see, the SOAP envelope can have two subsections, a header and a body. The header contains metadata about the message that is used for specific processing (this is the place for authentication tokens or timestamps and the like). Inside the body, you have the guts of the message, or a SOAP fault.

SOAP messages are rather simple in their syntax, but there are a few rules of the road that the good service provider will follow when handcrafting a message:

  • Use XML as the encoding mechanism.

  • Use the SOAP envelope namespace:

    <soap:Envelope
        xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    
  • Use the SOAP encoding namespace, by adding it to your envelope:

    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
        soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    
  • You cannot use Document Type Definition (DTD) references.

  • You cannot use XML processing directives.

Figure 10.5. The structure of a SOAP message

The structure of a SOAP message

Faulty Service

If you want to provide a nice experience for consumers of your service, you will need to take the time to make sure you understand the fault element. Fault messages need to be in the body, and they can appear only once. A fault message will contain details about the exception (as appropriate) and one of the fault codes defined by the SOAP specification.

WSDL Documents: Describing the Service Endpoints

Once you've created a service, what's next? You need a way of describing this service and its endpoints to potential consumers. Fortunately, there's a convenient way to do this.

What Are Endpoints?

According to Wikipedia, "A communication endpoint is an interface exposed by a communicating party or by a communication channel." The W3C has a more complete definition: an endpoint is "an association between a fully specified interface binding and a network address, specified by a URI that may be used to communicate with an instance of a web service." More simply, you can think of a friend's telephone number as an endpoint. When you call your friend, you are asking your service provider to connect your phone to her phone, thereby linking your endpoint with hers.

WSDL is an XML format for publishing network services. It describes a set of endpoints that operate on messages, which are abstract descriptions of the data being exchanged. Operations are likewise described abstractly and bound to a concrete network protocol and message format, which constitutes an endpoint.

The WSDL document itself has three parts:

Definitions

Definitions can be about data types as well as messages. They are expressed in XML using a mutually agreed-upon vocabulary. This allows you to adopt industry-based vocabularies for greater interoperability in a specific industry segment.

Operations

Web services support four basic operation types:

One-way request

Only the service endpoint receives a message.

Request/response

The endpoint receives a message and responds to the sender accordingly.

Solicit response

The endpoint initiates a message and expects a response.

Notification

The endpoint sends out a message without expecting a response.

Service bindings

The service bindings allow for the connection of a port type to an actual port. In other words, they tie the protocol and message format to a specific port. These bindings are typically created using SOAP.

A service binding might look something like this:

<service name="MyService" interface="tns:MyInterface">
   <endpoint name="MyServiceRestEndpoint"
       binding="tns:MyInterfaceHttpBinding"
       address="http://my.example.com/rest/"/>
   <endpoint name="MyServiceSoapEndpoint"
       binding="tns:MyInterfaceSoapBinding"
       address="http://my.example.com/soap/"/>
</service>

The Universal Description, Discovery, and Integration (UDDI) registry has made the process of finding web services infinitely easier. UDDI is a platform-independent, XML-based registry that allows service vendors to list themselves on the Internet. As an open industry initiative, UDDI is sponsored by the Organization for the Advancement of Structured Information Standards (OASIS). UDDI enables businesses to publish service listings, discover one another's services, and define how the services or software applications interact over the Internet.

A UDDI business registration consists of three components:

White pages

Contain addresses, contacts, and known identifiers

Yellow pages

Provide industrial categorizations based on standard taxonomies

Green pages

Hold technical information about services exposed by the business

UDDI is designed to be interrogated by SOAP messages. It provides access to WSDL documents describing the protocol bindings and message formats required to interact with the web services listed in its directory.

UDDI Data Types

UDDI defines four essential data types:

BusinessEntity

The top-level structure. It describes a business or other entity for which information is being registered.

BusinessService

A structure that represents a logical service classification. The element name includes the term "business" in an attempt to describe the purpose of this level in the service-description hierarchy. It can contain one or more bindingTemplates.

bindingTemplate

A structure that contains the information necessary to invoke specific services, which may require bindings to one or more protocols (such as HTTP or SMTP).

tModel

A technical "fingerprint" for a given service, which may also function as a namespace to identify other entities, including other tModels.

How do all these pieces-UDDI, WSDL, and SOAP-actually work together to get the work of web services done? Take a look at Figure 10.6, "The web service lifecycle".

Figure 10.6. The web service lifecycle

The web service lifecycle

The eight steps in the web service lifecycle are:

  1. Somewhere in the world a client wants to use a web service, so it seeks out a directory service.

  2. The client connects to the directory to discover a relevant service.

  3. By asking the directory service about the services available, the client is able to determine the presence of a service that meets the client's criteria.

  4. The directory contacts the service vendor to check on availability and validity.

  5. The service vendor sends the client a WSDL document.

  6. A proxy class is used to create a new instance of the web service.

  7. SOAP messages originating from the client are sent over the network.

  8. Return values are sent as a result of executing the SOAP message.

This isn't that bad, is it? What's more, Microsoft's WCF and Visual Studio tools make implementing a Service-Oriented Architecture very easy. Let's roll up our sleeves and see how WCF helps you get SOA implementations done fast.

The WCF team at Microsoft has been trying to deliver three big items to the development community. The design goals include:

  • Interoperability across platforms

  • Unification of existing technologies

  • Enabling service-oriented development

With the release of .NET 3.5, Microsoft is delivering on all fronts.

To maximize interoperability across platforms, WCF's architects chose SOAP as the native messaging protocol. This makes it possible for WCF applications running on Windows to reliably communicate with legacy applications, Mac OS X machines, Linux machines, Windows clients, Solaris machines, and anyone else out there who abides by the Web Services Interoperability Organization (WS-I) specification. (The WS-I is an industry consortium chartered to promote interoperability among the stack of web services specifications.)

To unify existing technologies, WCF takes all the capabilities of the distributed systems' technology stacks and overlays a simplified clean API in System.ServiceModel. Thus, you are able to accomplish the same things that previously required ASMX, WSE, System.Messaging, .NET remoting, and other enterprise solutions, all from within WCF. This helps cut down a developer's time to implementation and reduces the complexity of dealing with distributed technologies.

The WCF team has faced up to the future in a big way. Designed from the ground up to facilitate the business orientation of modern software projects, WCF enables rather than hinders the design and implementation of SOA. WCF allows you to build on object orientation and take on the service orientation required of today's distributed systems.

.NET 3.5 allows a very flexible approach to programming, providing a great set of mix-and-match ways to tackle most programming challenges you'll face. You can use configuration files, you can tap into the object model programmatically, and you can use declarative programming. Odds are that in most cases you will utilize all of these approaches, leveraging the strengths of each while minimizing your exposure to their respective weaknesses.

The ABCs of WCF

Every client needs to know the ABCs of a contract in order to consume a service: the address indicates where messages can be sent, the binding tells you how to send the messages, and the contract specifies what the messages should contain.

Addresses

As you might imagine, addressing is an essential component of being able to utilize a web service. An address is comprised of the following specifications:

Transport mechanism

The transport protocol to employ

Machine name

A fully qualified domain name for the service provider

Port

The port to use for the connection (as the default port is 80, specifying the port is not necessary when using HTTP)

Path

The specific path to a service

The format of a correctly specified service address is as follows:

protocol://<machinename>[:port]/<pathToService>

WCF supports a number of protocols, so we'll take the time to outline the addressing formats of each:

HTTP

HTTP is by far the most common way you will address your service.

http://silverlightconsulting.info/OrderStatus/GetShippingInfo

<endpoint
    address="http://silverlightconsulting.info/OrderStatus/GetShippingInfo"
    bindingSectionName="BasicHttpBinding"
    contract="IGetShippingInfo" />

For secure communication you only need to substitute https for http, and you're good to go.

Named pipes

When you need to do inter-process or in-process communication, named pipes are probably your best choice. The WCF implementation supports only local communication, as follows:

net.pipe://silverlightconsulting.info/OrderStatus/GetShippingInfo

<endpoint
    address="net.pipe://silverlightconsulting.info/OrderStatus/GetShippingInfo"
    bindingSectionName="NetNamedPipeBinding"
    contract="IGetShippingInfo" />
TCP

This protocol is very similar to HTTP:

net.tcp://silverlightconsulting.info/OrderStatus/GetShippingInfo

<endpoint
    Address="net.tcp://silverlightconsulting.info/OrderStatus/GetShippingInfo"
    bindingSectionName="NetTcpBinding"
    contract="IGetShippingInfo" />
MSMQ

Finally, if you need asynchronous messaging patterns, you will want to use a message queue. Microsoft's Message Queue (MSMQ) can typically be accessed through Active Directory. In an MSMQ message, port numbers don't have any meaning:

net.msmq://my.info/OrderStatus/GetShippingInfo

<endpoint
    Address="net.msmq://my.info/OrderStatus/GetShippingInfo"
    bindingSectionName="NetMsmqBinding"
    contract="IGetShippingInfo" />Binding

Bindings

Bindings are the primary driver of the programming model of WCF. The binding you choose will determine the following:

  • The transport mechanism

  • The nature of the channel (duplex versus request/response, etc.)

  • The type of encoding (XML, binary, etc.)

  • The supported WS-* protocols

Tip
Web service specifications are occasionally referred to collectively as "WS-*," though there is not a single managed set of specifications that this consistently refers to, nor a recognized owning body across them all.

WCF gives you a default set of bindings that should cover the bulk of what you will need to do. If you come across something that falls outside the bounds of coverage, you can extend CustomBinding to cover your custom needs. Just remember, a binding needs to be unique in its name and namespace for identification purposes.

If you are looking for complete interoperability, your first (and obvious) choice of bindings will be anything in the WS-prefixed set. If you need to bind to pre-WCF service stacks, you'll likely want to use the BasicHttpBinding. If you are only really servicing a Windows-centric environment without interoperability requirements, you can utilize the Net-prefixed bindings. Just remember that your choice of binding determines the transport mechanism you will be able to use.

Contracts

As we discussed earlier, one of the four tenets of service orientation is the notion of explicit boundaries. Contracts allow you to decide up front what you will expose to the outside world (the folks across the boundary). This frees you to work on the implementation without worry-as long as you uphold the contract, you are free to change the underlying implementation as needed. Therefore, contracts are one of the keys to interoperability among the many platforms from which your service might be called.

A WCF contract is essentially a collection of operations that specify how the endpoint in question communicates with the outside world. Every operation is a simple message exchange like the one-way, request/response, and duplex message exchanges.

Like a binding, each contract has a name and namespace that uniquely identify it. You will find these attributes in the service's metadata.

The class ContractDescription describes WCF contracts and their operations. Within a ContractDescription, every contract operation will have a related OperationDescription that will describe the aspects of the operation, such as whether the operation is one-way, request/response, or duplex. The messages that make up the operation are described in the OperationDescription using a collection of MessageDescriptions.

A ContractDescription is usually created from a .NET interface or class that defines the contract using the WCF programming model. This type is annotated with ServiceContractAttribute, and its methods that correspond to endpoint operations are annotated with OperationContractAttribute.

Talk Amongst Yourselves

The default pattern of message exchange is (surprise) the request/response pattern. Again, for those of you who have been making a living writing web-based software, this pattern should be very familiar. It is outlined in Figure 10.7, "The default request/response message exchange".

Figure 10.7. The default request/response message exchange

The default request/response message exchange

A duplex contract is more complex. It defines two logical sets of operations: a set that the service exposes for the client to call and a set that the client exposes for the service to call. When creating a duplex contract programmatically, you split each set into separate types (each type must be a class or an interface). You also need to annotate the contract that represents the service's operations with ServiceContractAttribute, referencing the contract that defines the client (or callback) operations. In addition, ContractDescription will contain a reference to each of the types, thereby grouping them into one duplex contract. This is really a peer-to-peer pattern, as illustrated by Figure 10.8, "Duplex messaging".

Figure 10.8. Duplex messaging

Duplex messaging

The last type of message pattern is the set-it-and-forget-it one-way messaging style. In this scenario, as seen in Figure 10.9, "One-way messaging", you send a message as a client, but you do not expect any sort of return message. This is often the behavior you engage in when dealing with message queues.

Figure 10.9. One-way messaging

One-way messaging

Now that you understand the basic nature of a WCF service, let's roll up our sleeves and create a service contract from scratch. This example will be based on our favorite fictional stock-quoting service, YahooQuotes. YahooQuotes provides stock quotes via the exposed behavior of the service. To make this a fully functional WCF service contract, you'll have to annotate the interface with both the ServiceContract and OperationContract attributes. You will also need to make sure you include the System.ServiceModel namespace, as shown here:

using System;
using System.ServiceModel;

A WCF service class implements a service as a set of methods. The class must implement at least one ServiceContract to define the operational contracts (i.e., methods) that the service will provide to the end user. Optionally, you can also implement data contracts that define what sort of data the exposed operations can utilize. You'll do that second.

Start by defining the interface of the service contract that defines a single operation contract for the YahooQuotes service:

namespace YahooQuotes.TradeEngine.ServiceContracts
{
   [ServiceContract(Namespace = "http://my.info/YahooQuotes")]
   public interface IYahooQuotes
   {
      [OperationContract]
      BadQuote GetLastTradePriceInUSD(string StockSymbol);
   }
}

That was simple enough. Now you need to implement the data contract for the BadQuote class:

namespace YahooQuotes.TradeEngine.DataContracts
{
   [DataContract(Namespace = "http://my.info/YahooQuotes")]
   public class BadQuote
   {
      [DataMember(Name="StockSymbol"]
      public  string StockSymbol;
      
      [DataMember(Name="Last"]
      public  decimal Last;
   
      [DataMember(Name="Bid"]
      public  decimal Bid;

      [DataMember(Name="Ask"]
      public  decimal Ask;
 
      [DataMember(Name="TransactionTimestamp"]
      private  DateTime TransactionTimestamp;

      [DataMember(Name="InformationSource"]
      public  decimal InformationSource;
   }
}

There may come a time when you decide you want more control over the SOAP envelope that WCF generates. When that time comes, you can annotate your class with the MessageContract attribute and then direct the output to either the SOAP body or the SOAP header by utilizing the MessageBody and MessageHeader attributes:

namespace YahooQuotes.TradeEngine.MessageContracts
{
   [MessageContract]
   Public class YahooQuotesMessage
   {
      [MessageBody]
      public string StockSymbol;

      [MessageBody]
      public decimal Last;

      [MessageBody]
      public decimal Bid;

      [MessageBody]
      public decimal Ask;

      [MessageBody]
      private DateTime TransactionTimestamp;

      [MessageHeader]
      public string InformationSource;
   }
}

In this case, you've specified that the InformationSource should be in the SOAP header by annotating it with the MessageHeader attribute. It is nice to be able to do this sort of thing, so keep it around in your bag of tricks to use as appropriate.

In the next chapter we'll build a complete YahooQuotes service and explore the WCF SOA programming model in greater detail.

Did you find this helpful?
(1500 characters remaining)
Thank you for your feedback
Show:
© 2014 Microsoft. All rights reserved.