Customizing and Extending the BizTalk WCF Adapters

Introduction

The contents of the following post are taken from a presentation I created and delivered at TechReady 9 in July 2009 and replicated with Stephen Kaufman at Tech-Ed Europe 2009 .

The ABC of WCF

Windows Communication Foundation (WCF) is a runtime and a set of APIs for exchanging messages between components and applications. WCF was designed according to the tenets of service orientation and unified the existing communication technologies like .NET Remoting and ASMX web service into a single programming model and consistent architecture which provides high levels of functionality, interoperability and extensibility. As you know, a typical WCF service can expose one or multiple endpoints. In general, endpoints provide clients access to the functionality offered by a WCF service. Each endpoint consists of 3 properties as depicted in the picture below:

  • An address that indicates where the endpoint can be found.
  • A binding that specifies how a client app can communicate with the endpoint.
  • A contract that identifies the operations exposed by the endpoint.

WCF_ABC

WCF Architecture: Messaging Runtime

  • The WCF runtime is divided into 2 primary layers as shown by the following picture:
    The Service Layer aka Service Model defines the mechanisms and attributes used by developers to define and decorate service, message and data contracts.
  • The  Messaging Layer  is responsible for preparing a WCF message for transmission on the send side and produce a WCF message for the dispatcher on the receive side. The messaging layer accomplishes this task using a Channel Stack. This latter is a pipeline of channel components that handle different processing tasks.  Each channel stack is composed of exactly one transport channel, one message encoder, and zero or more protocol channels.

WCF_Layers

It’s the responsibility of the proxy component on the client side and dispatcher component on the service side to mediate and translate between the two layers. In particular, the proxy component transforms .NET method calls into Message objects, whereas the dispatcher component turns WCF Messages into .NET method calls. WCF uses the Message class to model all incoming/outgoing messages within the Messaging Layer. The message represents a a SOAP Envelope, and therefore it’s composed of a payload and a set of headers. A typical WCF communication can be described as follows:

  1. The client application creates one or more input parameters. Each of these parameters is defined by a data contract.
  2. The client application invokes one of the methods of the service contract exposed by the proxy.
  3. The proxy delivers a WCF Message object to the channel stack.
  4. At this point each protocol channel has a chance to operate on the message before the transport channel uses a message encoder to transmit the final Message as a sequence of bytes to the target service. Each protocol channel can modify the content or the headers of the message to implement specific functionalities or WS-* protocols like WS-AtomicTransaction, WS-Security.
  5. The raw stream of data is transmitted over the wire.
  6. On the service side, the transport channel receives the stream of data and uses a message encoder to interpret the bytes and to produce a WCF Message object that can continue up the channel stack. At this point each protocol channel has a chance to work on the message.
  7. The final Message is passed to the Dispatcher.
  8. The Dispatcher receives the WCF Message from the underlying channel stack, individuates the target service endpoint using the destination address and Action property contained in the Message, deserializes the content of the WCF Message into objects.
  9. Finally the target service method is invoked.

WCF Binding Comparison

Bindings provide a mechanism for configuring channel stacks. A binding defines a precise recipe for building a channel stack using a transport channel, a message encoder, and a set of protocol channels.
WCF ships with several built-in bindings that target common communication scenarios.

Binding Class Name Transport Message Encoding Message Version Security Mode Reliable Messaging Tx Flow*
BasicHttpBinding HTTP Text SOAP 1.1 None X X
WSHttpBinding HTTP Text SOAP 1.2 WS-A 1.0 Message Disabled WS-AT
NetTcpBinding TCP Binary SOAP 1.2 Transport Disabled OleTx
NetNamedPipesBinding Named Pipes Binary SOAP 1.2 Transport X OleTx
NetMsmqBinding MSMQ Binary SOAP 1.2 Message X X
CustomBinding You decide You decide You decide You decide You decide You decide

 

You should select the most appropriate binding based on your needs:

  • For example, BasicHttpBinding is designed for interoperability with simple web services that conform to the SOAP 1.1 message version.
  • Instead the WSHttpBinding is designed for interoperability with more advanced web services that might leverage different WS-* protocols. Both of these bindings use HTTP for the transport and the text message encoding because they are designed for maximum interoperability.
  • NetTcpBinding and NetNamedPipeBinding, on the other hand, are designed for efficient and performant communication with other WCF applications across machines or on the same machine respectively.
  • If you need maximum flexibility and you need to use one or multiple custom protocol channels at runtime, you can use the CustomBinding that gives you the possibility to decide which binding elements compose your binding.

Bindings have different characteristics in terms of response time and throughput, so the general advice to increase performance is using the NetTcpBindind and NetNamesPipeBinding whenever possible.

BizTalkServiceInstance Class

Each WCF Receive Location in BizTalk Server is indeed an instance of a WCF Service Class called BizTalkServiceInstance hosted by a separate instance of a ServiceHost-derived class

  • the BtsServiceHost for RLs running in an in-process host
  • the WebServiceHost for RLs running in an isolated host

When you “enable” a WCF receive location, the adapter initializes and opens the ServiceHost, which dynamically builds the WCF runtime components within the BizTalk service process (BtsNtSvc.exe for in in-process host, w3wp.exe for an isolated host). This includes the channel stack, dispatcher, and the singleton service instance. WCF Receive and Send Ports are message-type agnostic or if you prefer untyped. This design comes in handy when you need to configure a single Receive Port to accept numerous message types or versions that you can normalize (via BizTalk maps or using a custom pipeline component) into a common message type before being posted the BizTalkMsgBoxDb. However, this design also implies that the WCF adapters will need to build on generic service contracts in order to remain message-type agnostic within the WCF implementation.

WCF Receive Locations have the responsibility to receive the incoming message bytes, perform any necessary SOAP and WS-* processing, and publish the message (or some part of it) to the message box. The WCF Adapters create a separate ServiceHost and singleton service object of this class for each receive location to handle client requests for the lifetime of the BizTalk Host instance running WCF receive locations. The service object uses multiple threads to process messages concurrently unless the WCF-NetMsmq receive locations are used with the Ordered processing property being selected.. As shown in the picture below, the class is decorated with the ServiceBehavior attribute:

BizTalkServiceInstance class

 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]internal sealed class BizTalkServiceInstance : ITwoWayAsync,                                                ITwoWayAsyncVoid,                                                IOneWayAsync,                                                IOneWayAsyncTxn,                                                ITwoWayAsyncVoidTxn{    ...}

 

In particular, you can note that:

-
InstanceContextMode = InstanceContextMode.Single

-
ConcurrencyMode = ConcurrencyMode.Multiple

Hence, all incoming messages to a WCF Receive Location are received and processed by a single well-known instance of the BizTalkServiceInstance class. This allows to avoid service activation/deactivation costs and improve performance/scalability.

The BizTalkServiceInstance class implements multiple untyped, generic service contracts.

-
IOneWayAsync

-
IOneWayAsyncTxn

-
ITwoWayAsync

-
ITwoWayAsyncVoid

-
ITwoWayAsyncVoidTxn

Each contract was designed for a different scope (as suggested by their name):

-
OneWay vs TwoWay Message Exchange  Pattern

-
Transactional vs Non-Transactional Communication

 [ServiceContract(Namespace = "https://www.microsoft.com/biztalk/2006/r2/wcf-adapter")]public interface IOneWayAsync{    // Methods    [OperationContract(AsyncPattern = true, IsOneWay = true, Action = "*")]    IAsyncResult BeginOneWayMethod(Message message, AsyncCallback callback, object state);    [OperationContract(IsOneWay = true, Action = "BizTalkSubmit")]    void BizTalkSubmit(Message message);    void EndOneWayMethod(IAsyncResult result);}[ServiceContract(Namespace = "https://www.microsoft.com/biztalk/2006/r2/wcf-adapter")]public interface IOneWayAsyncTxn{    // Methods    [OperationContract(AsyncPattern = true, IsOneWay = true, Action = "*")]    IAsyncResult BeginOneWayMethod(Message message, AsyncCallback callback, object state);    [OperationContract(IsOneWay = true, Action = "BizTalkSubmit")]    void BizTalkSubmit(Message message);    void EndOneWayMethod(IAsyncResult result);}[ServiceContract(Namespace = "https://www.microsoft.com/biztalk/2006/r2/wcf-adapter")]public interface ITwoWayAsync{    // Methods    [OperationContract(AsyncPattern = true, IsOneWay = false, Action = "*", ReplyAction = "*")]    IAsyncResult BeginTwoWayMethod(Message message, AsyncCallback callback, object state);    [OperationContract(IsOneWay = false, Action = "BizTalkSubmit")]    Message BizTalkSubmit(Message message);    Message EndTwoWayMethod(IAsyncResult result);}[ServiceContract(Namespace = "https://www.microsoft.com/biztalk/2006/r2/wcf-adapter")]public interface ITwoWayAsyncVoid{    // Methods    [OperationContract(AsyncPattern = true, IsOneWay = false, Action = "*", ReplyAction = "*")]    IAsyncResult BeginTwoWayMethod(Message message, AsyncCallback callback, object state);    [OperationContract(IsOneWay = false, Action = "BizTalkSubmit")]    void BizTalkSubmit(Message message);    void EndTwoWayMethod(IAsyncResult result);}[ServiceContract(Namespace = "https://www.microsoft.com/biztalk/2006/r2/wcf-adapter")]public interface ITwoWayAsyncVoidTxn{    // Methods    [TransactionFlow(TransactionFlowOption.Mandatory)]    [OperationContract(AsyncPattern = true, IsOneWay = false, Action = "*", ReplyAction = "*")]    IAsyncResult BeginTwoWayMethod(Message message, AsyncCallback callback, object state);    [TransactionFlow(TransactionFlowOption.Mandatory), OperationContract(IsOneWay = false, Action = "BizTalkSubmit")]    void BizTalkSubmit(Message message);    void EndTwoWayMethod(IAsyncResult result);}

 

All the methods exposed by these service contracts are generic, asynchronous and untyped. In fact, as shown in the picture above, each of this method is decorated by the OperationContract attribute and in particular:

-
AsyncPattern = True  indicates that an operation is implemented asynchronously using a Begin<methodName> and End<methodName> method pair in a service contractAction = “*” means that the method accepts a message with any Action.

-
ReplyAction = “*” means that the method can return a message with any Action.

-
Every method accepts as parameter or returns a generic WCF Message.

As a consequence, each WCF Receive Location can accept multiple  message types and versions that can be normalized into a canonical format using a different map before being published to the MessageBox.

Also Send Ports are message-type agnostic.

One-Way WCF Receive Locations

When you define a One-Way WCF Receive Location that uses the NetMsmqBinding, the underlying WCF service will expose an endpoint which uses the IOneWayAsync service interface. If instead the One-Way WCF Receive Location is not configured to use NetMsmqBinding, the underlying WCF service will expose an endpoint using the ITwoWayAsyncVoid contract interface that returns an acknowledgment message. Otherwise, when you define a two-way WCF receive location, the underlying WCF service will expose an endpoint using the ITwoWayASync service interface.

As you can note in the picture above, the IOneWayAsync service contract has a single logical operation named OneWayMethod that matches all incoming messages (Action=”*”). It’s implemented with the WCF asynchronous programming model that ties two methods – BeginOneWayMethod and EndOneWayMethod – together via AsyncPattern=true.

ITwoWayAsyncVoid is similar in design except that it also returns a WCF Message object (notice the addition of ReplyAction=”*”) and the operation is not marked as one-way. The only difference with ITwoWayAsync is that it also returns a Message object in order to properly model two-way ports.  The following picture depicts what happens when a message is received and processed through a One-way WCF Receive location.

  1. The Raw Message Data are sent over the wire.
  2. The Transport Channel receives and decodes the incoming stream of bytes and creates a WCF Message that is processed through the Channel Stack.
  3. The WCF message is passed on to the Dispatcher
  4. The WCF message is passed on to the BizTalkServiceInstance.
  5. Based on the RL configuration, the entire SOAP Envelope, the Body of the SOAP message or a specific Xml Element is used as content of the BizTalk message.
  6. The BizTalk message is processed through the pipeline.
  7. A Map is eventually applied.
  8. The BizTalk message is published to the MessageBox.

WCF_OneWay

WCF Adapters

The WCF Adapters provided by BizTalk correspond 1:1 to the most commonly used WCF bindings.

Adapter Name WCF Binding Name When to use?
WCF-BasicHttp BasicHttpBinding When you need interoperability with WS-I Basic Profile 1.1 services, such as those created with ASP.NET Web services (ASMX) or other first-generation service frameworks
WCF-WSHttp WSHttpBinding When you need interoperability with more advanced services that leverage WS-* protocols, such as those created with WCF or other modern service frameworks
WCF-NetTcp NetTcpBinding When you need efficient inter-machine communication with other WCF applications
WCF-NetNamedPipe NetNamedPipeBinding When you need efficient intra-machine communication with other WCF applications
WCF-NetMsmq NetMsmqBinding When you need durable, asynchronous communication with other WCF applications (using MSMQ as the underlying transport)
WCF-Custom Any When you need to define a custom binding configuration for an “in-process” host
WCF-CustomIsolated Any When you need to define a custom binding configuration for an “isolated” host – this is only a receive adapter, not used on send ports

 

WCF-Custom and WCF-CustomIsolated Adapters

The WCF-Custom and WCF-CustomIsolated adapters offer you complete control over the channel stack and behaviors configuration, and as a consequence, they are the only WCF adapters you really need. Compared with the other WCF Adapters, they are the only ones to provide the possibility to:

-
Implement and exploit extensibility points.

-
Have full access to properties exposed by bindings/behaviors.

-
Enable the use of the bamInterceptor endpoint behavior.

-
Export/Import the binding configuration.

-
Disable a receive location on failure.

-
Run an http-based RL within an in-process host.

-
Use bindings (e.g. wsDualHttpBinding) for which a WCF Adapter does not exist.

WCF allows developers to modify and extend its standard runtime behavior with several extensibility points, some of which are not supported by BizTalk Server: for example you cannot customize the BizTalkServiceInstance class, create you own ServiceHost or create a custom ContractBehavior. BizTalk Server supports the following extensibility points:

-
Custom Behaviors

  -   
    Service Behaviors: they enable the customization of the entire service runtime including the ServiceHost.
      
  -   
    Endpoint Behaviors: they enable the customization of service endpoints and their associated EndpointDispatcher. The most common technique is creating an endpoint behavior to add a Message Inspector to the collection of Message Inspectors used at run time by a proxy/dispatcher. This allows to intercept an in-flight incoming/outgoing WCF message before this latter is passed/transmitted to the intended operation/target service, inspect and eventually change its content (headers or body).
      
  
  • Custom Binding Elements, Channels Binding Elements, Channels, Channel Factories, Binding Element Extension, etc. This technique is more complex, because in order to register and execute at runtime a custom channel within the channel stack used by a WCF Receive Location or Send Port, it’s necessary to create and properly register multiple components:

    • Custom BindingElementExtensionElement.

    • Custom BindingElement.

    • Custom ChannelFactory

    • Custom Channel.

  • Custom Bindings: the WCF LOB Adapter SDK allows developers to create  new bindings to use with WCF-Custom and WCF-CustomIsolated Adapters. For example, the WCF based SQL Adapter (WCF-SQL) is based on a new binding called sqlBinding that is properly registered in the machine.config when installing the Adapter.

In my previous post  called How to Throw Typed Fault Exceptions from Orchestrations Published as WCF Services I created 2 different Endpoint Behaviors to customize the default runtime behavior of the WCF-Custom/WCF-CustomIsolated Adapter. In my post entitled How to create a custom WCF Channel that debatches an inbound message I show how creating a custom channel to debatch (on a WCF Send Port) an inbound message containing a collection of operations and make multiple calls to the underlying WCF service, one for each operation.

Conclusions

I strongly suggest you to read the following whitepapers to have a better insight in WCF Adapters and their extensibility points.

  • The Using the Windows Communication Foundation (WCF) Adapters in BizTalk Server whitepaper describes the use of the WCF adapters in BizTalk Server.
  • The Consuming and Hosting WCF Services with Custom Bindings in BizTalk Server whitepaper provides an in-depth explanation on how to use the BizTalk Server WCF adapters for hosting and consuming Windows Communication Foundation (WCF) services with custom bindings. The paper compiles a series of lessons learned based on a real-world implementation of integrating a custom WCF binding with the WCF adapters. Furthermore, key industrial infrastructure concerns such as transaction management and security are discussed in the context of integrating custom WCF bindings and behaviors with the BizTalk Messaging Engine. Also emphasized are a few pragmatic paradigms such as the use of dynamic ports in consuming WCF services. Finally, some key integration challenges are discussed to streamline the correct use of the adapters for solving complex business problems.

Moreover, I recommend to download and review the following WCF Adapters samples on MSDN: