Microsoft Windows Communication Foundation 4.0 Cookbook for Developing SOA Applications

5 (1 reviews total)
By Steven Cheng
    What do you get with a Packt Subscription?

  • Instant access to this title and 7,500+ eBooks & Videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Working with Contracts

About this book

The Windows Communication Foundation 4.0 (WCF 4.0) is a .NET-based application programming interface for building and running connected systems. It enables secure and reliable communication among systems within an organization or across the Internet. This book deals with the difficult issues faced by a .NET developer while working with WCF.

WCF 4.0 is a communications infrastructure that unifies a broad array of distributed systems' capabilities in a composable, extensible architecture that supports multiple transports, messaging patterns, encodings, network topologies, and hosting models. This book is a collection of focused real-world recipes and covers basic recipes on topics such as working with contracts to more advanced topics such as extending WCF runtime. By the end of this book you will have valuable information that helps transform the potentially unproductive habits of .Net developers who work with WCF.

This book will take you through many concepts starting with complete support for contract-related design for WCF service development. You will learn to use WCF's built-in feature for building various service endpoints. Service hosting and configuration are important areas for building WCF services, especially at the service deployment stage, and are detailed in this book. You will find it easy to work with WCF client proxy generation and metadata publishing and discovery when you go through recipes such as customizing auto-generated service proxies.

The author then discusses the exchange of data in WCF service operation features, related to WCF data serialization. You will discover some useful tips for security in WCF service development and built-in features for developing concurrency control for your services built upon it.

One big plus is that you will learn to extend the existing WCF framework to achieve advanced functionality. You will find a dedicated chapter for RESTful and AJAX-enabled service development. Moving on, you will find several useful WCF service interoperability cases, which are important for a distributed service development platform. Towards the end of this book you will find some handy and useful diagnostic methods for troubleshooting.

Publication date:
October 2010
Publisher
Packt
Pages
316
ISBN
9781849680769

 

Chapter 1. Working with Contracts

In this chapter, we will cover:

  • Defining a one-way Contract

  • Making DataContract forward-compatible

  • Generate DataContract from XML Schema

  • Using XMLSerializer to control message serialization

  • Using MessageContract to control the SOAP Message

  • Adding a custom SoapHeader via Contract

  • Returning custom exception data through FaultContract

 

Introduction


Contracts often occur in business affairs to restrict the operations between the operators that are working with each other. For distributed communication services, Contracts also play a very important role in making sure that the service consumers can co-operate with the service providers correctly. Looking around, we can see the term SOA (Service-Oriented Architecture) being widely used. Technically speaking, SOAP (Simple Object Access Protocol) can be explained as a set of components that can be invoked, and whose interface descriptions can be published and discovered. From an SOA perspective, with Contracts properly defined, service consumers can get an idea of how to work with the target service without knowing how the service is actually implemented.

As a unified communication programming platform, WCF provides complete support for Contract-related design in various parts of WCF service development. These include ServiceContract, OperationContract, DataContract, MessageContract, FaultContract, and so on. ServiceContract and OperationContract are used to represent a Service and its operations' definition (such as the operation collection and operation signatures). DataContract is used to represent an agreement of the data that will be exchanged between the service client and server. If the service designer wants to take full control over the data envelope transferred between client and server, they can use MessageContract to control the underlying service messages. WCF also provides FaultContract for the service designer to declaratively associate custom Exception types to certain service operations, and the corresponding fault content will be returned when an error occurs.

This chapter provides seven recipes on how to work with various contracts in WCF service development. These include defining a one-way service operation that helps you get familiar with standard ServiceContract and OperationContract declaration. Next, we will cover how to use FaultContractAttribute to associate a custom SOAP fault data type with certain service operations that need a customized error format. With the third, fourth, and fifth recipes, we will focus on DataContract designing topics, such as DataContract versioning, using XMLSerializer for the DataContract types serialization, and the contract-first approach for DataContract generation. The last two recipes describe how to use MessageContract to perform low-level manipulation on the service operations message formatting, such as returning arbitrary XML data as message content and adding a custom SOAPHeader through MessageContract class members.

 

Defining a one-way Contract


One-way (also called diagram-style) operation is a common pattern in distributed communication programming and is also one of the three supported message exchange patterns in WCF. When using the one-way message exchange pattern, a client sends a message using a fire-and-forget exchange (refer to the next screenshot). A fire-and-forget exchange is one that requires out-of-band confirmation of successful delivery. The message might be lost in transit and never reach the service. If the send operation completes successfully at the client end, it does not guarantee that the remote endpoint has received the message. In those cases where the client only wants to send information to the server side, without taking care of the execution result, we can consider defining our WCF service operation as one-way style.

How to do it...

  1. Create the service interface or class type and add methods into it.

  2. Mark the interface/class type with ServiceContractAttribute and mark the methods with OperationContractAttribute.

  3. Set the IsOneWay property of the OperationContractAttribute to true.

    The following code snippet shows the complete one-way OperationContract definition:

    [ServiceContract]
    interface IMyContract
    {
    [OperationContract(IsOneWay=true)]void OneWayMethod(){
        // Do some work here
    }
    }

How it works...

When OperationContract is marked with IsOneWay=true, the runtime will detect this and know that this service operation needs to be handled as one-way style. One-way operation cannot carry a return value but can only pass input parameters to the service. After the client sends out the service request, the client will wait until it gets the response that the request message has reached the service side. However, the response here is not the return value, but the protocol level ACK, which indicates that the request has reached the service (but gives no idea of whether or how the request has been processed).

We can get further understanding on one-way operation via the following question:

What is the difference between a standard void (no return value) operation and a one-way operation?

Suppose you have the following ServiceContract implemented:

[ServiceContract]
 public interface IHelloService
 {
     [OperationContract(IsOneWay=false)]
     void DoWork();

     [OperationContract(IsOneWay = true)]
     void DoWorkAsOneWay();
}

By invoking the two operations from the client and capturing the HTTP message, we can get different response messages as shown in the next two screenshots. The first screenshot shows the response of the DoWork operation, while the next shows the response of the DoWorkAsOneWay operation.

As you can see, the normal void operation will return HTTP 200 status code and the complete SOAP Response in the body, while the one-way operation will only return a HTTP 202 Accepted status header. This indicates that the one-way operation call gets finished as long as the server side received the request, while the normal void operation (standard request/reply) will wait for the server side to execute and return the response data. Understanding this can help us to make better decisions about whether to use one-way operation or not.

There's more...

In addition to one-way operation, there are two other message exchange patterns that are widely used in WCF services. They are the Request-response pattern and the Duplex pattern.

The Request-response pattern is very similar to the standard function call that has an input parameter and return value. In a Request-response pattern-based WCF service operation call, a message is sent and a reply is received. The pattern consists of request-response pairs, as shown in the next figure.

The Duplex exchange pattern allows an arbitrary number of messages to be sent by a client and received in any order. This pattern is like a phone conversation, where each word being spoken is a message (refer to the following screenshot).

See also

  • Capture a raw http request/response of WCF service call in Chapter 12

  • Complete source code for this recipe can be found in the \Chapter 1\recipe1\ folder

 

Make DataContract forward-compatible


WCF uses a serialization engine called DataContractSerializer by default, to serialize and deserialize data. If we want to add new complex data types (that will be transferred in service operations) in a WCF service, we need to define it as a DataContract type so as to make it friendly to the DataContractSerializer engine. A .NET serialization system supports backward-compatibility on custom data types naturally. However, sometimes we also need forward-compatibility for data types used in a WCF service. Suppose that you have a service that exchanges some custom data types between clients. If one side updates the custom data type (adds some fields or properties) or uses a newer version, it is important to make sure that the other side (without using the updated version of data) can still work correctly with the updated data type instances.

How to do it...

  1. Make the custom data type (we will use in our service communication) implement the IExtensibleDataObject interface.

    [DataContract]
        public class FCQuestion : IExtensibleDataObject
        {
            [DataMember]
            public string Subject { get; set; }
            [DataMember]
            public string Answer { get; set; }
          
            public ExtensionDataObject ExtensionData
            {
                get;
                set;
            }
        }
  2. Make sure you haven't enabled the IgnoreExtensionDataObject property on ServiceBehaviorAttribute applied on your WCF service (this property is disabled by default).

    You can have a look at the article ServiceBehaviorAttribute.IgnoreExtensionDataObject Property for more information and is available at:

    http://msdn.microsoft.com/en-us/library/system.servicemodel.servicebehaviorattribute.ignoreextensiondataobject.aspx

How it works...

After the DataContract type implements the IExtensibleDataObject interface, an ExtensionDataObject property is added; this property plays an important role in forward-compatible serialization. WCF will use DataContractSerializer for DataContract type serialization/deserialization. When DataContractSerializer finds that a certain type (used for operation parameters or return value) has implemented the IExtensibleDataObject interface, it will store any data (this is obtained from the message stream during deserialization) that doesn't have corresponding property/fields in the type definition into the ExtensionDataObject property so that these data will not get lost. And if the deserialized instance (with some unknown data stored in ExtensionDataObject) is serialized into the message later, DataContractSerializer will write out ExtensionDataObject into the message stream again. This ensures that the data in the new version of DataContract can be consumed by the service/client with the old type definition correctly, instead of raising unexpected type, mismatching, or serialization exceptions.

The following modified data type can be consumed by the service/client that has the old definition, as explained earlier, without synchronizing the DataContract type definition:

[DataContract]
    public class FCQuestion : IExtensibleDataObject
    {
        [DataMember]
        public string Subject { get; set; }
        [DataMember]
        public string Answer { get; set; }
        [DataMember]
        public string Comment { get; set; }

        public ExtensionDataObject ExtensionData
        {            get; set;       }
    }

There's more...

Currently, using the IExtensibleDataObject interface can make the DataContractSerializer preserve unknown data properties/fields when deserializing/serializing custom data types. However, the ExtensionDataObject property is an opaque object to developers and we do not have means to manually read the data stored in it. In case we want to manually extract the additional unknown property/fields, we can consider directly accessing the underlying SOAP message via MessageInspector or other extension points.

See also

  • Altering an operation message via MessageInspector in Chapter 9.

  • Complete source code for this recipe can be found in the \Chapter 1\recipe2\ folder

 

Generate DataContract from an XML Schema


In the contract-first development approach, one of the most important steps is to generate the data types used in the service from XML Schemas, which represent the contract. As a unified distributed communication development platform, it is quite common to support such kind of DataContract generation in WCF development.

Getting ready

If you are not yet familiar with the contract-first development approach, you can get a quick overview of it from Aaron Skonnard's MSDN article Contract-First Service Development at http://msdn.microsoft.com/en-us/magazine/cc163800.aspx.

How to do it...

  1. Compose the XML schema that represents the DataContract types that will be used in our WCF service. The next screenshot shows a simple sample schema that contains a simple enum and a complex data type definition:

  2. Use WCF ServiceModel Metadata Utility Tool (Svcutil.exe) to generate DataContract type source code based on the XML Schema composed in step 1. Following is the sample command on how to use the Svcutil.exe tool:

    svcutil.exe /target:code /dataContractOnly /serializer:DataContractSerializer /importXmlTypesTestDataContractSchema.xsd
    

    The generated DataContract is as follows:

    public enum LevelEnum : int
        {
            [System.Runtime.Serialization.EnumMemberAttribute()]
            Low = 2,
            …………….
        }
           …………..
        [System.Runtime.Serialization.DataContractAttribute(Name="TestData", Namespace="http://wcftest.org/datacontract")]
        public partial class TestData : object, System.Runtime.Serialization.IExtensibleDataObject
        {
            ………………….
          
            [System.Runtime.Serialization.DataMemberAttribute(IsRequired=true, Order=2)]
            public wcftest.org.datacontract.LevelEnum EnumProperty
            {            }
    }
  3. Use the generated DataContract in our WCF service as operation parameters or return type.

    [ServiceContract]
        public interface ITestService
        {
            [OperationContract]
            TestData GetData();
        }

How it works...

The contract-first development approach is contract/schema driven; the developers need to author the metadata/contract of the service/data. For the previous example, TestDataContractSchema.xsd provides the contract definition of two types that will be used in our WCF service.

Svcutil.exe is a very powerful tool provided in the .NET 3.5 SDK. If you're familiar with ASP .NET ASMX Web Service development, you will find it similar to the wsdl.exe tool. You can generate a WCF client proxy and export metadata from service code. Here we just use it to generate serialization code from the given XML Schema. In the previous sample, we specify DataContractSerializer as the serialization type (you can also use XMLSerializer instead, if you prefer XML serialization-oriented code).

By capturing the service operation's underlying SOAP message on wire (refer to the next screenshot), we can find that the return value's XML payload conform to the XML Schema we provided as the generation source (TestDataContractSchema.xsd):

There's more...

The DataContract we generated here includes two typical class types—a composite type and a simple enum type. In most scenarios, people will define much more complicated data types in their services, and WCF DataContractSerializer does provide enough support for mapping between an XML Schema-based contract and .NET code-based types. You can get more information on type mapping in the MSDN document Data Contract Schema Reference, available at:

http://msdn.microsoft.com/en-us/library/ms733112.aspx.

See also

  • Creating a typed service client in Chapter 4

  • Complete source code for this recipe can be found in the \Chapter 1\recipe3\ folder

 

Using XMLSerializer to control message serialization


By default, WCF runtime uses DataContractSerializer to perform data serialization and deserialization. However, in some cases, we will prefer using XMLSerializer, which will give developers more control over the serialized XML content or will work more closely with some POX clients (like ASMX Web Service client).

How to do it...

  1. First, we should make our data type ready for XMLSerializer. This can be done by adding XML serialization attributes on our data types. The following User class has been decorated with several XML serialization attributes (XmlRootAttribute for top-level type and XmlElementAttribute for type members).

    [XmlRoot(ElementName="UserObject",Namespace="http://wcftest.org/xmlserializer")]
        public class User
        {
            [XmlElement(ElementName="FName")]
            public string FirstName { get; set; }
            [XmlElement(ElementName = "LName")]
            public string LastName { get; set; }
            [XmlElement(ElementName = "IsEnabled")]
            public bool Enabled { get; set; }
        }
  2. Then, we need to apply XmlSerializerFormatAttribute on the ServiceContract type used in our service (see the ITestService interface shown as follows):

        [ServiceContract]
        [XmlSerializerFormat(Style=OperationFormatStyle.Document)]
        public interface ITestService
        {
            [OperationContract]
            void SendUser(User user);
        }

How it works...

When we apply the XmlSerializerFormatAttribute on the ServiceContract, the WCF runtime will use XMLSerializer as the default Serializer to serialize data and deserialize SOAP messages. Also, the auto-generated service metadata will output the data type schema based on the class's XML serialization attributes. For the User class mentioned in the previous code example, service metadata will use the schema as shown in the next screenshot to represent its XML format:

By capturing the underlying SOAP message, we can find that the XML content of the serialized User object conforms to the metadata schema defined earlier, which is controlled by those XML serialization attributes applied on the user class (refer to the next screenshot):

See also

  • Complete source code for this recipe can be found in the \Chapter 1\recipe4\ folder

 

Using MessageContract to control the SOAP message


DataContract can help us design the data types used in a WCF service. However, this only covers the data members (variables and parameters used in operation) serialized in the underlying SOAP message. Sometimes we also need to control the structure and format of the entire SOAP message.

WCF introduces a MessageContract concept, which helps service developers to model the structure and format of the entire message of a given service operation. Actually, we can take MessageContract type as a special DataContract type, which is marked by the MessageContractAttribute. This recipe will show you how we can define a typical MessageContract for our WCF service operation to control the format of the underlying SOAP XML message.

How to do it...

  1. Define a custom data type that represents the entire SOAP message body content. Use MessageContractAttribute to decorate the type and MessageBodyMemberAttribute to mark class members that will be embedded in the SOAP message body. The following code demonstrates a sample MessageContract pair—one is for operation request and the other for operation response.

        [MessageContract(WrapperName="Hello",WrapperNamespace="http:// wcftest.org/messagecontract")]
        public class HelloRequest
        {
           [MessageBodyMember(Name="Who")]
           public string User { get; set; }
        }
     [MessageContract(WrapperName="HelloResponse",WrapperNamespace="http://wcftest.org/messagecontract")]
        public class HelloResponse
        {
            [MessageBodyMember(Name="Reply")]
            public string ReplyContent { get; set; }
        }
  2. After defining the MessageContract types for request/response operation, we need to use them as the input parameter (the only input parameter) and return value of the operation's implementation (see the following SayHello operation):

    [OperationContract]
    HelloResponse SayHello(HelloRequest req);

    In the SayHello operation, HelloRequest is the only input parameter and HelloResponse represents the return value.

How it works...

Types marked with MessageContractAttribute can be used to represent the entire SOAP envelope body. The serialization of such types still follows the rules for normal DataContract types.

Also, it is important that operations which use MessageContract to control the SOAP envelope only have a single input parameter and return value. This is because only that input parameter will be serialized as the entire SOAP request body, and the return value will be serialized as the entire SOAP response body.

By capturing the SOAP request/response on wire, we can find that the serialized SOAP message content conforms to the MessageContract definition (refer to the next two screenshots):

See also

  • Creating a service via ChannelListener in Chapter 5

  • Complete source code for this recipe can be found in the \Chapter 1\recipe5\ folder

 

Adding a custom SoapHeader via Contract


The SOAP message (used by an XML Web Service and WCF service) is a standard XML document consisting of a root Envelope tag, which in turn consists of a required Body element and an optional Header element. Each sub element under the optional Header is called a SoapHeader , which plays a similar role as the other headers, uses a certain network protocol's transmit package.

A SoapHeader is often used in SOAP messages to carry some application protocol-level data in addition to the SOAP body. WCF has used many built-in SoapHeaders for certain protocols it supports (WS-Security, WS-Reliability, and so on). For some user scenarios, we will also need to add a custom SoapHeader into the WCF service message so as to exchange additional information (mostly for communication purposes).

How to do it...

  1. We need to define a custom type, which represents the SoapHeader that will be serialized in the service message. Here is a sample DataContract type that represents a custom header used for custom authentication:

    [DataContract]
        public class MyUsernameToken 
        {
           [DataMember]
           public string Username { get; set; }
           [DataMember]
           public string Password { get; set; }
        }
  2. Next, we can apply the custom Header type into our service operation's MessageContract. What we should do here is mark the MessageContract member (of the Header type) with MessageHeaderAttribute.

    [MessageContract]
        public class HelloRequest
        {
            [MessageHeader]
            public MyUsernameToken AuthUser { get; set; }
    
            [MessageBodyMember]
            public string User { get; set; }
        }
        [MessageContract]
        public class HelloResponse
        {
            [MessageBodyMember]
            public string Reply { get; set; }
        }
  3. At the end, we need to use the MessageContract type as the only input parameter/return value of the particular service operation.

How it works...

The MessageHeaderAttribute helps mark the particular type member (of MessageContract type) as the SoapHeader that will be embedded in the resulting SOAP Envelope. Also, since the header is added in MessageContract at design-time, the WCF auto-generated metadata will include the SoapHeader information, as shown in the following screenshot:

If you use Visual Studio or Svcutil.exe to generate the client proxy class, the generated proxy type will automatically map the SoapHeaders to operation parameters. Thus, when invoking the service operation, we can simply pass SoapHeader data as the operation parameter. The following code demonstrates how the auto-generated service proxy invokes the operation with the custom SoapHeader assigned.

private static void CallService()
  {
      TestProxy.TestServiceClient client = new TestProxy.TestServiceClient();

      TestProxy.MyUsernameToken utoken = new TestProxy.MyUsernameToken{ Username="Foo", Password="Bar"};
      string reply = client.SayHello(utoken, "WCF user");

      Console.WriteLine(reply);
  }

By capturing the underlying SOAP message, we can find that the MyUsernameToken header type is serialized as a SoapHeader within the <Header> section.

There's more...

WCF supports various means to add custom SoapHeader a into service messages. This recipe demonstrates using a custom type and MessageContract to add a custom SoapHeader statically. In addition to this, we can also use code to programmatically add SoapHeaders into service messages.

See also

  • Using MessageContract to control the SOAP message

  • Adding a dynamic SoapHeader into a message in Chapter 5

  • Securing a dynamic SoapHeader in Chapter 7

  • Complete source code for this recipe can be found in the \Chapter 1\recipe6\ folder

 

Return custom exception data through FaultContract


In an XML Web Service and WCF service, the server side will return any unhandled exception as SoapFault in the returned message. For WCF service operations, exceptions are returned to the client through two steps:

  • Map exception conditions to custom SOAP faults

  • Services and client send and receive SOAP faults as exceptions

By default, WCF will return the simple error message or complete exception information (including Callstack) as the Fault content. However, sometimes we want to encapsulate the raw exception information or return some user-friendly error to the client side. To support this kind of customized exception-information format, WCF has provided the FaultContract and FaultException features. FaultException is a new exception type that uses Generic to help WCF service encapsulate various kinds of custom error data objects in a unified way. FaultContract is used to formally specify the type of FaultException that will be returned from the target WCF service operation, so that the client consumers can properly handle and parse it.

How to do it...

  1. First, create the custom error type that will be returned to the service client as exception information. The custom error type is defined as a standard DataContract type.

  2. Then, apply the custom error type to the service operation (which will return this custom error type) through a FaultContractAttribute.

  3. The following code shows a sample custom error type and the service operation that applies it:

      [DataContract]
        public class UserFriendlyError
        {
            [DataMember]
            public string Message
            { get;set; }
        }
    
    [ServiceContract]
        public interface ICalcService
        {
            [OperationContract]
            int Divide(int lv, int rv);
    
            [OperationContract]
            [FaultContract(typeof(UserFriendlyError))]
            int DivideWithCustomException(int lv, int rv);
    }
  4. Finally, we need to add our exception handling code in the service operation's implementation and return the custom error type through the FaultException<T> type (see DivideWithCustomException method shown as follows):

    public int Divide(int lv, int rv)
    {
        if (rv == 0) throw new Exception("Divided by Zero is not allowed!");
        return lv / rv;
            }
    
    public int DivideWithCustomException(int lv, int rv)
    {
        if (rv == 0) throw new FaultException<UserFriendlyError>(new UserFriendlyError() { Message = "Divided by Zero is not allowed!" }
           );
        return lv / rv; 
    }

How it works...

The FaultContractAttribute applied on the service operation will make the runtime generate corresponding metadata entries in the WSDL document (as shown in the next screenshot). Thus, the generated client proxy knows how to handle this custom error type.

When invoking the operation, we can add code to handle the specific FaultException and get user-friendly error information from the Exception.Detail property.

try
{
     //call the operation with invalid parameter
}
catch (FaultException<UserFriendlyError> fex)
{
     Console.WriteLine("Error: {0}", fex.Detail.Message);
}

If we use Fiddler or message logging to inspect the underlying SOAP message, we can also find the custom error data in XML-serialized format:

There's more...

Since the custom error type used by FaultContract supports any valid DataContract type, we can define various kinds of custom exception data content (from simple primitive types to complex nested classes).

See also

  • Generating DataContract from XML Schema

  • Capturing a WCF request/response message via Fiddler tool in Chapter 12

  • Complete source code for this recipe can be found in the \Chapter 1\recipe7\ folder

About the Author

  • Steven Cheng

    Steven Cheng is a senior support engineer at Microsoft Global Technical Support Center where he has been supporting Microsoft software development technologies for more than 5 years. Currently, as a community leader, he is working actively in the MSDN newsgroup and forum communities.

    Steven Cheng's technical specialties cover many popular areas of Microsoft development technologies including .NET framework, ASP.NET, XML WebService, Windows Communication Foundation, SharePoint development, and so on. His blog can be found at http://blogs.msdn.com/stcheng.

    Browse publications by this author

Latest Reviews

(1 reviews total)
Microsoft Windows Communication Foundation 4.0 Cookbook for Developing SOA Applications
Unlock this book and the full library FREE for 7 days
Start now