December 2008 - Posts

Using XAML serialization in WCF 4.0

Declarative Services is one of the exciting new features of Windows Communication Foundation (WCF) 4.0. By declarative, we are referring to services that are completely modeled by using the Extensible Application Markup Language (XAML). As you might think, this capability will open to door for a whole new set of scenarios in Service Oriented systems which are really hard to implement with the current technologies. The specific capabilities of declarative services will be the subject of a future post. Today, I would like to explore one of the features that enable the implementation of declarative services: XAML serialization.

You don’t really need to know a lot about declarative service to figure out that there it must be a component that handles the translation between XAML and CLR types. This is precisely the role of the XamlServices class included in the System.Runtime.Xaml namespace. This class implements the serialization and deserialization process between XAML and .NET types and consequently it’s a key component of the declarative services infrastructure. Although we can currently use different mechanisms for implementing Xaml serialization, XamlServices exposes a programming model considerably simpler than other alternatives.

Let’s take the following class definition.

   1:     public class Contact
   2:      {
   3:          private string firstName;
   4:          private string lastName;
   5:          private DateTime birthDay;
   6:   
   7:          public Contact()
   8:          { }
   9:   
  10:          public string FirstName
  11:          {
  12:              get { return firstName; }
  13:              set { firstName = value; }
  14:          }
  15:   
  16:          public string LastName
  17:          {
  18:              get { return lastName; }
  19:              set { lastName = value; }
  20:          }
  21:   
  22:          public DateTime BirthDay
  23:          {
  24:              get { return birthDay; }
  25:              set { birthDay = value; }
  26:          }
  27:      }

In order to serialize an instance of the Contact class into XAML we can use the XamlServices class as illustrated in the following code.

   1:    private static void XamlSerializationSample()
   2:          {
   3:              Contact contact = new Contact();
   4:              contact.FirstName = "fn";
   5:              contact.LastName = "ln";
   6:              contact.BirthDay = DateTime.Now;
   7:              XmlWriter writer = XmlWriter.Create(file path...);
   8:              XamlServices.Save(writer, contact);
   9:          }

The output of the serialization looks like the following.

   1:  <?xml version="1.0" encoding="utf-8"?>
   2:  <Contact BirthDay="2008-12-16T19:58:14.1173568-08:00" FirstName="fn" LastName="ln" 
                xmlns="clr-namespace:XamlSerialization;assembly=XamlSerialization" />

Additionally, we can use a similar algorithm to deserialize the XAML representation into an instance of the contact class.

   1:    private static void XamlDeserializationSample()
   2:          {
   3:              XmlReader reader= XmlReader.Create(file path...);
   4:              Contact contact= (Contact)XamlServices.Load(reader);
   5:          }

Implementing content based routing using the Windows Application Server (Dublin) forwarding service

Dublin’s application server incorporates a series of runtimes services that complement the runtime behavior of a WCF service host on areas such as lifecycle, persistence, message routing, etc. Among those services, the forwarding services provides high performance message routing across different services. By providing a robust foundation for messaging routing, Dublin’s forwarding service can address really complex service composition and endpoint virtualization scenarios which are traditionally very hard to implement in real world SOA applications. Capabilities such as service aggregation, content-based routing, protocol translation or data partitioning are notorious for requiring a lot of infrastructure logic in order to work properly and consequently can be drastically simplified by the use of a technology like the forwarding service.

Dublin’s forwarding service proposes a versatile model for message routing based on the concepts of WCF filters and filter tables. This post does not intend to explain the intricacies of the forwarding service; instead we are going to explore a practical example of how to leverage this new technology to implement a traditional intelligent endpoint routing scenario.

Our scenario starts with a service hosted on multiple endpoints across a server farm. Messages targeted to that service will be routed to different endpoints depending on its content. Additionally, the rules that control the content can be subject to frequent changes that need to be incorporates without impacting the different endpoints. By using Dublin’s application service, we could conceive the following topology to address that scenario.

On this scenario, the forwarding service leverages XPath message filter and filter tables to dynamically route messages to the different service’s endpoints. For the simplicity of our example let’s assume our target service implements the following contract that processes a financial transaction.

 

   1:  [ServiceContract]
   2:  public interface IService
   3:  {
   4:   
   5:      [OperationContract]
   6:      bool ProcessTrasaction(Transaction transaction);
   7:   
   8:  }
   9:   
  10:  [DataContract]
  11:  public class Transaction 
  12:  {
  13:      private string transactionId;
  14:      private double amount;
  15:      private string customerId;
  16:   
  17:      [DataMember]
  18:      public string TransactionId
  19:      {
  20:          get { return transactionId; }
  21:          set { transactionId = value; }
  22:      }
  23:   
  24:      [DataMember]
  25:      public double Amount
  26:      {
  27:          get { return amount; }
  28:          set { amount = value; }
  29:      }
  30:   
  31:      [DataMember]
  32:      public string CustomerId
  33:      {
  34:          get { return customerId; }
  35:          set { customerId = value; }
  36:      }
  37:   
  38:  }

 

 

The service implementation not really relevant to this example. In order to distribute the message traffic we have decided to host the service on multiple endpoints as illustrated in the following configuration file.

   1:  ...
   2:      <services>
   3:              <service name="Service" behaviorConfiguration="ServiceBehavior">
   4:                  <!-- Service Endpoints -->
   5:                  <endpoint address="/ep1" binding="basicHttpBinding" contract="IService">
   6:          
   7:                      <identity>
   8:                          <dns value="my server"/>
   9:                      </identity>
  10:                  </endpoint>
  11:   
  12:          <endpoint address="/ep2" binding="basicHttpBinding" contract="IService">
  13:         
  14:            <identity>
  15:              <dns value="my server"/>
  16:            </identity>
  17:          </endpoint>
  18:   
  19:          <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
  20:              </service>
  21:          </services>
  22:  ...

No need to mention that real world scenarios might require way more complex topologies :)

Now that we have our sample service hosted on multiple endpoints, it is time to enable certain level of intelligent routing between the these endpoints. In order to accomplish that, we should host an instance of the Dublin’s forwarding service and configure the appropriated routing rules. However, before we get to that point, we should enable a couple of artifacts in a global configuration file like machine.config. Specifically, we should add the forwarding behavior to the behavior extensions list so that it can be accessible by the forwarding service.

   1:  ...
   2:  <behaviorextensions>
   3:   
   4:  <add name="forwardingbehavior" 
                          type="microsoft.processserver.messaging.configuration.forwardingbehaviorextensionelement,
                          microsoft.processserver.messaging, version=3.0.0.0, culture=neutral,
                          publickeytoken=31bf3856ad364e35"/>
   5:   
   6:  <add name="marshalingbehavior" 
                          type="microsoft.processserver.messaging.configuration.marshalingextensionelement, 
                          microsoft.processserver.messaging, version=3.0.0.0, culture=neutral,
                          publickeytoken=31bf3856ad364e35"/>
   7:   
   8:  </behaviorextensions> 
   9:  ...

Additionally, we should also add the filtering configuration section which details the specific syntax for expressing routing rules.

   1:  ...
   2:  <configsections>
   3:   
   4:  <sectiongroup name="system.servicemodel" type="system.servicemodel.configuration.servicemodelsectiongroup, 
                                       system.servicemodel, version=3.0.0.0, culture=neutral, 
                                       publickeytoken=b77a5c561934e089">
   5:   
   6:  <section name="filtering" type="microsoft.processserver.messaging.configuration.filteringsection, 
                         microsoft.processserver.messaging, version=3.0.0.0, culture=neutral, 
                         publickeytoken=31bf3856ad364e35"/>
   7:   
   8:  </sectiongroup>
   9:   
  10:  </configsections>
  11:   
  12:  ...

At this point we are ready to configure a new forwarding service. we can do that by simply hosting the ForwardingService service as illustrated in the following .svc file.

Now its time for to configuring the routing rules for the different service’s endpoints. When we say configure we literally mean it :). Implementing the routing rules is purely a configuration exercise that leverages the XPath message filter and filter tables among other artifacts. For our example, we will configure a couple of basics rules that determines if a transaction is over $50000.

   1:  ...
   2:  <system.serviceModel>
   3:          <services>
   4:              <service behaviorConfiguration="forwardingConfig" 
                            name="Microsoft.ProcessServer.Messaging.ForwardingService">

5: <endpoint address="RequestReply" binding="basicHttpBinding" name="reqReplyEndpoint"

contract="Microsoft.ProcessServer.Messaging.IRequestReplyDatagram"/>

   6:              </service>
   7:          </services>
   8:          <bindings>
   9:              <basicHttpBinding>
  10:                  <binding name="BasicHttpBinding_IService">
  11:                      
  12:                      <security mode="None">
  13:                          <transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
  14:                          <message clientCredentialType="UserName" algorithmSuite="Default"/>
  15:                      </security>
  16:                  </binding>
  17:              </basicHttpBinding>
  18:          </bindings>
  19:          <behaviors>
  20:        
  21:              <serviceBehaviors>
  22:                  <behavior name="forwardingConfig">
  23:                      <forwardingBehavior filterTableName="contentFilterTable" filterOnHeadersOnly="false"/>
  24:            
  25:            <serviceMetadata httpGetEnabled="true"/>
  26:                  </behavior>
  27:                  <behavior name="ServiceBehavior">
  28:                    
  29:                      <serviceMetadata httpGetEnabled="true"/>
  30:                    
  31:                      <serviceDebug includeExceptionDetailInFaults="false"/>
  32:                  </behavior>
  33:              </serviceBehaviors>
  34:          </behaviors>
  35:          <client>
  36:              <endpoint address="http://localhost:49159/SampleService/Service.svc/ep1" binding="basicHttpBinding" 
                             bindingConfiguration="BasicHttpBinding_IService" 
                             contract="*" name="BasicHttpBinding_IService1"/>

37: <endpoint address="http://localhost:49159/SampleService/Service.svc/ep2" binding="basicHttpBinding"

bindingConfiguration="BasicHttpBinding_IService"

contract="*" name="BasicHttpBinding_IService2"/>

  38:          </client>
  39:          <!--FILTERING SECTION-->
  40:          <filtering>
  41:              <filters>
  42:                  <filter name="transactionFilter1" filterType="XPath" 
                               filterData="boolean(//*[local-name()= 'Amount']/text() &gt; 50000)"/>
  43:                  <filter name="transactionFilter2" filterType="XPath" 
                               filterData="boolean(//*[local-name()= 'Amount']/text() &lt; 50000)"/>
  44:              </filters>
  45:              <filterTables>
  46:                  <table name="contentFilterTable">
  47:                      <filters>
  48:                          <add filterName="transactionFilter1" mappedValue="BasicHttpBinding_IService1"/>
  49:                          <add filterName="transactionFilter2" mappedValue="BasicHttpBinding_IService2"/>
  50:                      </filters>
  51:                  </table>
  52:              </filterTables>
  53:          </filtering>
  54:      </system.serviceModel>
  55:  ...

Notice that the filter table "contentFilterTable" in line 46 associates specific filters (lines 42-43) with client's (lines 36-37) configured to forward the message to a service endpoint. In our case, we have a couple of mutually exclusive rules which determine that one endpoint will process the transactions larger than $50000 while the other will process the rest of the transactions.

With this simple configuration we leverage Dublin’s forwarding service to distribute messages across different service’s endpoints based on XPath Boolean expressions. It is important to notice that the forwarding service can leverage any WCF message filters such as Address, Endpoint, XPath, etc. Additionally, developers can create their own message filter and integrate it with the forwarding service.

.

RESTful.NET

RESTful.NET, the latest book from my friend Jon Flanders,  is now available at Amazon and O'Reilly. This book does an amazing job exploring the WCF-REST programming model and its relationship with other technologies. Definitely this book is a MUST READ for developers interested on RESTful architectures.

Congrats Jon!!!

More Posts