Export (0) Print
Expand All

Using the Windows Communication Foundation (WCF) Adapters in BizTalk Server

Published: October 2008

Author: Aaron Skonnard, Pluralsight

Applies to: BizTalk Server 2006 R2

To download a copy of this article, go to http://go.microsoft.com/fwlink/?LinkID=131728.

Microsoft® BizTalk® Server has long supported Web services as a primary communication technique but the support has been fairly limited to date. For example, developers working with BizTalk Server 2006 can use the built-in SOAP adapter to achieve “basic profile” service integration or the downloadable Web Services Enhancements (WSE) 2.0 adapter when support for the various WS-Security specifications is required. But that’s as far as these existing adapters can take you in today’s maturing service-oriented landscape. Developers working in more modern service-oriented environments, which build on the various WS-* protocols, have been unable to fully utilize BizTalk Server 2006 in such environments since the product lacked support for Windows® Communication Foundation (WCF) within the messaging layer.

Fortunately, with the release of BizTalk Server 2006 R2, developers will find a set of new WCF adapters that offer full integration with the advanced WS-* specifications supported by the WCF runtime. These adapters target the most common WCF communication scenarios and make them easy to tackle. As with the earlier SOAP/WSE adapters, developers can use the tools provided with the WCF adapters to publish WCF services from orchestrations or schemas and to consume external services using a variety of different transport, encoding, and protocol options, offering unparalleled service-oriented flexibility. The remainder of this white paper provides in-depth coverage on using the new WCF adapters.

Bb967002.note(en-US,BTS.10).gifNote
If you’re new to using Web services in BizTalk Server 2006, check out “BizTalk Server 2006 Web Services” at http://go.microsoft.com/fwlink/?LinkId=101734 for some relevant background information before continuing.

As part of the Microsoft .NET Framework 3.0, WCF provides a new communication “foundation” that enables .NET-based applications to exchange information with other applications via messaging. The “other” applications aren’t required to use WCF since it builds on today’s open Web service protocols and standards for interoperability. However, if the “other” applications do choose to use WCF, numerous optimizations are possible that allow the interactions to perform more like a .NET Remoting or COM+ solution.

As a result, WCF unifies the various distributed programming frameworks produced by Microsoft over the last decade through a simple programming model that accommodates numerous messaging scenarios. The WCF runtime manages the complexities behind the scenes and simplifies the general surface area for developers. The unification will undoubtedly make things easier in the years ahead.

Before diving into the WCF adapter details, let’s briefly review the basics of the WCF programming model, the runtime architecture, and the concept of bindings.

Programming Model

WCF provides a simple programming model for describing service contracts and message exchange patterns by using traditional .NET class/interface definitions annotated with special WCF attributes.

Figure 1 provides a simple example. The Invoice class represents a simple data contract (the XML that will appear in a SOAP message) while IBillingService represents a service contract (a message exchange). BillingService is a WCF service class that implements IBillingService.

Figure 1: The WCF Programming Model

[DataContract(Namespace="http://example.org/billing")]
public class Invoice
{
    [DataMember] public string InvoiceId;
    [DataMember] public string CustomerName;
    [DataMember] public DateTime InvoiceDate;
    [DataMember] public double InvoiceTotal;
}

[ServiceContract(Namespace="http://example.org/billing")]
public interface IBillingService
{
    [OperationContract ]
    void SubmitInvoice(Invoice invoice);
    ... // remaining operations omitted
}
public class BillingService : IBillingService
{
    ... // service implementation omitted
}

In this example, SubmitInvoice uses a typed contract (the Invoice class) to constrain the incoming message and it doesn’t return a reply message (notice the void return type). However, despite the void return type, SubmitInvoice is still officially a request-reply operation (in terms of WSDL), which allows WCF to return fault messages to the caller when necessary. In order to officially make SubmitInvoice a one-way operation, you must set IsOneWay=true on [OperationContract] as illustrated here:

[ServiceContract(Namespace="http://example.org/billing")]
public interface IBillingService
{
    [OperationContract(IsOneWay=true)]
    void SubmitInvoice(Invoice invoice);
    ... // remaining operations omitted
}

Making this operation one-way changes the WSDL port type definition and tells WCF that it cannot return any response to the caller. As you’ll see shortly, one-way operations are not compatible with most of the BizTalk WCF adapters due to the way the adapters were designed.

When a message arrives at an endpoint, the WCF dispatcher determines which operation to invoke based on the “action” value found in the message. Since we didn’t specify an explicit “action” value on SubmitInvoice (via [OperationContract]’s Action property), WCF assumes a default action value based on the service contract namespace, service contract name, and operation name (in this case “http://example.org/billing/IBillingService/SubmitInvoice”).

Hence, only messages carrying a matching “action” value will be dispatched to the SubmitInvoice method at run time, during which process the body of the message will be deserialized.

If you don’t wish to impose typed contracts on the incoming/outgoing messages, WCF allows you to define service contracts in terms of the generic Message type. You can even choose to process all request messages by a single operation by specifying Action=”*” on [OperationContract]. You can also specify that this operation can process any reply message by specifying ReplyAction=”*”. The following example shows a generic service contract that contains a one-way and request-reply operation:

[ServiceContract(Namespace="http://example.org/generic")]
public interface IGenericContract
{
    [OperationContract(Action="*")]
    void SubmitAnything(Message request);
    [OperationContract(Action="*", ReplyAction="*")]
    Message SubmitAndReceiveAnything(Message request);
}

Although it’s probably more common for WCF developers to program with typed service contracts, the flexibility of generic service contracts can become very useful in certain scenarios. As you’ll see shortly, this particular design feature is used quite heavily by the new WCF adapters.

Hosting Services

WCF makes it easy to host service classes, like the BillingService class above, in any .NET Framework 3.0 application domain. You can host WCF services in Internet Information Services (IIS) versions 5.x, 6.0, and 7.0 in order to benefit from the simplicity and manageability of the IIS environment. Or you can “self-host” services in the .NET application of your choice (such as a long-running Windows service or a client-side WinForm application). Self-hosting is accomplished by constructing and opening a ServiceHost instance as shown here:

...
ServiceHost host = new ServiceHost(typeof(BillingService));
host.Open(); // dynamically builds the WCF runtime components
...

When you do this, ServiceHost first builds an in-memory service description based on the attributes found on the service types and the information found in the WCF configuration section. Then it uses the service description to build the necessary runtime components when you call Open.

The host can expose one or more service endpoints to accommodate different communication needs. Each endpoint specifies an address, a binding, and a contract to use during communication. The address and binding tell the ServiceHost how to build the underlying messaging infrastructure while the contract primarily influences the message serialization and invocation process.

Developers typically use the WCF configuration section to specify endpoint details since it decouples the messaging configuration from the host application code (see Figure 2). This sample exposes two endpoints on the service – one that uses HTTP along with various WS-* protocols and another that uses raw TCP with more efficient Windows protocols. Both endpoints use the same contract.

Figure 2: The WCF Configuration Section

<configuration>
  <system.serviceModel>
    <services>
      <service name="BillingService">
        <endpoint address="http://server:8080/billing" 
                  binding="wsHttpBinding" 
                  contract="IBillingService"/>
        <endpoint address="net.tcp://server:8888/billing" 
                  binding="netTcpBinding" 
                  contract="IBillingService"/>
      </service>
    </services>
  </system.serviceModel>
</configuration>

Although this approach is common, you can also manipulate the host configuration manually if desired. For example, you can call ServiceHost.AddServiceEndpoint to add endpoints dynamically before calling ServiceHost.Open. This opens the door to numerous custom configuration possibilities, including storing WCF configuration information in the database of your choice. You’ll see that the new WCF adapters take advantage of this feature by storing WCF configuration information in the BizTalk Enterprise Single Sign-On (SSO) database.

The separation between the programming model and configuration system offers a key benefit to those using WCF – it allows developers to focus largely on business logic while authoring services, knowing that operations will be able to control different aspects of the runtime messaging configuration without requiring modifications to the code. Although there are still some design issues that developers and operations personnel will need to coordinate throughout the entire process, the separation of concerns creates new opportunities that didn’t exist before.

Calling Services

A beautiful thing about the WCF architecture is how the programming model is symmetric across services and clients. In other words, the same types we used to implement the BillingService (Invoice and IBillingService) can also be used to consume the service from within WCF client applications.

You do this by creating a channel with ChannelFactory. When you create a ChannelFactory, you specify the service contract type (IBillingService) the channel will implement along with the target endpoint configuration. Configuring endpoints on the client side is very similar to what you saw in Figure 2. Here’s a simple example that shows how to call the SubmitInvoice operation from a WCF client application:

...
// initialize an Invoice object to use for the request message
Invoice invoice = new Invoice();
invoice.CustomerName = "Contoso";
invoice.InvoiceId = Guid.NewGuid().ToString();
invoice.InvoiceDate = DateTime.Now;
invoice.InvoiceTotal = 100.00;

ChannelFactory<IBillingService> cf = 
    new ChannelFactory<IBillingService>("clientEndpointConfig");
IBillingService billingSvc = cf.CreateChannel();
billingSvc.SubmitInvoice(invoice);
...


Although the client/service applications can be programmed by using the same WCF contract definitions, it’s actually more common for each side to use its own representation of the contract. Typically the client contracts are generated from WSDL by using a tool like SvcUtil.exe. All that matters is that the contracts used on both sides agree on what the messages are supposed to look like on the wire.

For example, even if our sample service implements IBillingService, clients can still call it by using IGenericContract from client applications (assuming they know how to build the request message properly). The following example illustrates how you can accomplish this in code:

...
// this helper method creates a <SubmitInvoice> message manually
Message msg = CreateSubmitInvoiceMessage(); 

ChannelFactory<IGenericContract> cf = new ChannelFactory<IGenericContract>(
    new NetNamedPipeBinding());
IGenericContract billingSvc = cf.CreateChannel(
    new EndpointAddress("net.pipe://server/billing"));
billingSvc.SubmitAnything(msg);...

Clients can use a generic contract to integrate with any service contract implemented by a service, assuming the directionality is the same (one-way vs. request-reply). Now that we’ve covered the WCF programming model basics, let’s review what’s going on behind the scenes within the runtime.

For more information on the WCF programming model and configuration mechanisms, see “Learn the ABC’s of Programming Windows Communication Foundation” at http://go.microsoft.com/fwlink/?LinkId=101783.

Runtime Architecture

When you initialize a ServiceHost or a client-side proxy channel, WCF builds a runtime similar to what’s shown in Figure 3. The runtime is divided into two primary layers: the service layer and the messaging layer. The service layer (sometimes referred to as the “service model”) defines the primary user experience – here developers work with class/interface definitions and attributes while ignoring the underlying messaging details. It’s the responsibility of the proxy/dispatcher components to translate between the two layers – moving between .NET method calls and Message objects.

WCF uses the Message class to model all incoming/outgoing messages within the messaging layer. The Message class models a message as an XML Infoset that consists of a payload and a set of headers similar to SOAP. It’s the job of the messaging layer to either prepare Message objects for transmission (on the send side) or to produce Message objects for the dispatcher (on the receive side).

The messaging layer accomplishes this through what’s known as a “channel stack”. A channel stack is a pipeline of “channel” components that handle different processing tasks. Each channel stack consists of exactly one transport channel, one message encoder, and zero or more protocol channels.

Figure 3: WCF Runtime Architecture
Bb967002.3f4f78cb-c9c7-418e-8a7a-35e792cf9550(en-US,BTS.10).gif

Let’s take a closer look at what happens in the channel stack on the receive side. When a message arrives, the transport channel is responsible for reading the bytes off the wire. It uses a message encoder to interpret the bytes and to produce a WCF Message object that can continue up the channel stack. Message encoders build on some new System.Xml classes (XmlDictionaryReader/Writer) that enable reading/writing XML Infosets by using different encodings such as text, binary, or Message Transmission Optimization Mechanism (MTOM). This means the same logical message can be represented with many different byte representations.

Once the transport/encoder has produced a Message object, each protocol channel will have an opportunity to operate on it in a specific order. This is where WCF does the work to implement the WS-* protocols supported by WCF such as those related to security, reliable messaging, and transactions.

For example, if a secure message arrives with signatures and encrypted elements, it would be the job of the channel stack, and the security protocol channels specifically, to “unwind” the security headers before handing the Message object to the dispatcher. By the time the Message arrives at the dispatcher, the signatures will have been verified and any encrypted elements will have been decrypted.

The channel stack allows the dispatcher to focus squarely on message deserialization, service instancing, threading, and method invocation. However, when using generic service contracts (based on Message), the dispatcher does not need to worry about object serialization during the dispatching process. But that type of design does require your application code to deal with the Message objects directly.

The channel stack processing just described also takes place on the client-side, only the channel stack executes in reverse order as illustrated in Figure 3. The proxy delivers a Message object to the channel stack, at which point each protocol channel has a chance to operate on it before the transport channel uses a message encoder to transmit the final Message as a sequence of bytes.

For more information on the WCF messaging layer, see “WCF Messaging Fundamentals” at http://go.microsoft.com/fwlink/?LinkId=101787.

Bindings

In the end, you control a service’s messaging configuration by how you construct the channel stack. A simple “basic profile” channel stack will only consist of the HTTP transport channel, a text message encoder, and no additional protocol channels. However, for more sophisticated WS-* scenarios, the channel stack will need to be configured with many protocol channels organized in the right order.

Bindings provide a developer-friendly abstraction for configuring channel stacks. A binding defines a precise recipe for building a channel stack using a transport channel, a message encoder, and a suite of protocol channels. WCF ships with several built-in bindings that target common communication scenarios. Figure 4 lists some common WCF bindings and compares the differences between them.

Figure 4: WCF Binding Comparison

Binding Class Name Transport Message Encoding Message Version Security Mode RM 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

Bb967002.note(en-US,BTS.10).gifNote
X = Not Supported, WS-A = WS-Addressing, WS-AT = WS-AtomicTransactions, OleTx = OleTransactions

* Transaction flow is always disabled by default, but when you enable it, these are the default protocols.

For example, BasicHttpBinding is designed for interoperability with simple, first-generation services that conform to the WS-I Basic Profile 1.1 whereas WSHttpBinding is designed for interoperability with more advanced service configurations 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 communication with other WCF applications across machines or on the same machine respectively. Notice how they both use the binary encoding, transport security, and Windows protocols for efficiency.

When one of the built-in bindings doesn’t meet your exact needs, you can always define a binding configuration based on one of the built-in bindings as a starting point. Creating a binding configuration allows you to change the binding’s default settings but you cannot change everything. You can only change things that the author of the binding class meant for you to change. For example, you cannot change the BasicHttpBinding to use the binary message encoding because the binding was specifically designed for scenarios where you need interoperability and the binary encoding is specific to WCF.

In most situations you’ll probably be able to configure one of the built-in bindings to meet your needs but if not, you can define a new custom binding by configuring the built-in CustomBinding class (see Figure 4). Unlike the other built-in bindings, CustomBinding doesn’t come with any predefined settings or constraints. Instead you must specify all of the binding details yourself.

You can even take things one step further by defining a new custom binding class that you can use like any other built-in binding (simply derive your custom binding class from Binding).

For a closer look at configuring bindings and writing custom binding classes, see “WCF Bindings In-Depth” at http://go.microsoft.com/fwlink/?LinkId=101791.

In general, WCF provides a flexible messaging architecture that fits nicely in the world of BizTalk Server where the primary focus is message-based integration. The new WCF adapters complete the bridge between WCF and BizTalk Server 2006. In a nutshell, the WCF adapters make it possible to use WCF as the transport when configuring send ports and receive locations (see Figure 5).

Figure 5: Choosing a WCF Adapter
Bb967002.ae5dfbf5-4632-4d08-8571-eed9ef21a5df(en-US,BTS.10).gif

Using one of the new WCF adapters is like using any other BizTalk adapter. On the receive side, you create a receive location and choose one of the WCF adapters for the inbound transport. Likewise, on the send side, you create a send port and choose one of the WCF adapters for the outbound transport. Once you’ve selected a WCF adapter for a send/receive port, you can click the “Configure” button to configure the various WCF options available for that particular adapter.

When you configure a receive location to use one of the WCF adapters, the receive location dynamically creates a ServiceHost for a generic service capable of publishing incoming messages to the BizTalk message box. When you configure a send port to use a WCF adapter, it dynamically creates a generic channel capable of transmitting BizTalk messages to external services.

Figure 6 lists the various WCF adapters and describes their usage. As you can see, each of the WCF adapters corresponds to one of the built-in WCF bindings described in Figure 4 and targets a common WCF communication scenario. When you encounter scenarios that can’t be accommodated by one of the built-in WCF adapters, you can use the WCF-Custom or WCF-CustomIsolated adapters to define a custom WCF binding configuration to meet your precise communication needs.

The custom adapters offer you complete control over the WCF channel stack configuration, and as a result, they are the only WCF adapters you really need. However, they also require you to know quite a bit about WCF configuration and the various extensibility techniques. Hence, providing individual adapters targeted at today’s most common communication scenarios greatly simplifies the developer experience by hiding many of the unnecessary details related to those specific cases.

Figure 6: The WCF Adapters in BizTalk Server 2006 R2

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

Let’s start by taking a quick lap around using a few WCF adapters so you’ll be familiar with the basic usage before delving further into the architecture and configuration details.

Creating a WCF Send Port

We’ll start by creating a new send port that uses the WCF-NetTcp adapter to integrate with the WCF service shown earlier in Figure 1 and Figure 2. Our goal is to integrate with the TCP endpoint so we’ll need to select the WCF-NetTcp adapter for the transport as shown in Figure 7. Then we can click Configure to configure how the WCF-NetTcp adapter should be used.

Figure 7: Creating a WCF Send Port
Bb967002.2a1d5554-ae74-45d8-990f-df3b3096e8a9(en-US,BTS.10).gif

Figure 8 shows the configuration dialog box for the WCF-NetTcp adapter. Notice we have to specify the target address for the service endpoint – in this case “http://server:8888/billing”. We also need to specify the “action” for the operation. The expected action value for the SubmitInvoice operation shown in Figure 1 is http://example.org/billing/IBillingService/SubmitInvoice. The dialog box in Figure 8 provides additional tabs for further configuring the WCF binding, in this case NetTcpBinding.

Since the WCF sample shown in Figure 1 and Figure 2 uses all of the NetTcpBinding defaults, we don’t need to configure the WCF-NetTcp adapter beyond specifying the address and action values. However, we need to define when the send port should be activated by defining a send port filter (subscription).

For this example, let’s define a send port filter that matches all incoming messages received by a receive port named “ReceiveInvoices” (e.g., BTS.ReceivePortName == ReceiveInvoices). Once you “Start” the send port, all messages received via the “ReceiveInvoices” port will cause the send port to be activated.

Figure 8: Configuring the WCF-NetTcp Send Adapter
Bb967002.6e069f63-8587-4b05-b82b-b10c443ea4c6(en-US,BTS.10).gif

When activated, the send port places the body of the outbound BizTalk message in the body of a new Message object that it transmits via a channel based on the NetTcpBinding.

Creating a WCF Receive Location

Now let’s create a static one-way receive port named “ReceiveInvoices” that will publish incoming messages to the message box by using a WCF receive location. After we’ve created the new receive port, we can create a receive location that uses the WCF-NetNamedPipe adapter as shown in Figure 9.

Figure 9: Creating a WCF Receive Location
Bb967002.0fc07a52-c177-4732-8421-3376d51ea307(en-US,BTS.10).gif

Then we can configure the WCF-NetNamedPipe adapter (see Figure 10). These settings allow you to configure the binding details for the service endpoint that will be dynamically exposed when you enable the receive location. For this example, all we need to configure on the adapter is the endpoint address – we can accept the defaults for the remaining NetNamedPipeBinding settings.

Figure 10: Configuring the WCF-NetNamedPipe Adapter
Bb967002.51d47e42-db2e-409c-9b06-9fee27b7175d(en-US,BTS.10).gif

When you enable this receive location, the WCF adapter infrastructure initializes a ServiceHost for a generic service that knows how to publish incoming messages to the message box. The ServiceHost instance will be initialized with a single endpoint based on NetNamedPipeBinding, the address we specified in Figure 10, and a generic service contract based on the directionality of the receive port. We’ll cover the details of this built-in generic service and the generic contracts it uses shortly.

Calling BizTalk Server from a WCF Client

With this receive port in place, we can now write a traditional WCF client application to transmit messages to the (enabled) WCF receive location by using named pipes. The following example shows how to do this, assuming the client application has access to the WCF contracts shown in Figure 1:

Invoice invoice = new Invoice();
... // initialize Invoice object

ChannelFactory<IBillingService> cf = new ChannelFactory<IBillingService>(
    new NetNamedPipeBinding());
IBillingService billingSvc = cf.CreateChannel(
    new EndpointAddress("net.pipe://server/billing"));
billingSvc.SubmitInvoice(invoice);
...

When the SOAP message arrives at the WCF receive location, the internal WCF service will extract the body from the SOAP message and submit it to the message box. In this case the body looks like this:

<SubmitInvoice xmlns="http://example.org/billing">
  <invoice xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <CustomerName>Contoso</CustomerName>
    <InvoiceDate>2007-07-23T09:11:48.9595408-07:00</InvoiceDate>
    <InvoiceId>ebb00c59-48cc-414f-b1c9-2b5873561892</InvoiceId>
    <InvoiceTotal>100</InvoiceTotal>
  </invoice>
</SubmitInvoice>
...

When this message is published to the message box, the send port will be activated. At this point, the WCF adapter repackages the <SubmitInvoice> message in a Message object that it transmits by using a channel based on the NetTcpBinding and the address specified in the send port configuration. In this scenario, BizTalk Server is now a message broker between the WCF client/service applications.

The WCF adapters fit within the BizTalk Server publish/subscribe messaging architecture like any other BizTalk adapter, as illustrated in Figure 11. Let’s discuss the WCF send/receive adapter architectures in more detail in order to better understand the WCF adapter integration.

Figure 11: Using the WCF Adapters in Send/Receive Ports
Bb967002.e6d08cd9-dc6e-40f9-80b1-605c2d015b1d(en-US,BTS.10).gif

Send Adapter Architecture

The architecture for the send adapter is a little simpler than that for the receive adapter because it doesn’t have to deal with hosting issues. Send ports subscribe to messages in the message box. When a new message matches a send port filter, the send port is activated. When a WCF send port is activated, the WCF send adapter prepares the BizTalk message for outgoing transmission using a WCF channel.

Send ports are untyped by nature, which means the message provided to the WCF send adapter must already match the schema type expected by the target service (you can use a pipeline component or a map to produce the expected message type if necessary). The main thing you need to specify on the send port configuration is what “action” value to use in the generated WCF Message object.

The default behavior of the WCF send adapter is to use the body of the outgoing BizTalk message as the body of the new message that will be transmitted by WCF. However, you can control the structure of the outgoing WCF Message object by providing the WCF adapter with a custom XML template you’d like it to use around the body. We’ll cover how you configure message publishing options shortly.

An important consideration is that the WCF send adapter is only compatible with request-reply operations even when used on one-way send ports. WCF service operations can return void but they shouldn’t be marked with IsOneWay=true if you want to call them from a WCF send port. The only exception is when you’re using NetMsmqBinding, in which case the service operations must be one-way. This is a common for developers to stumble on when they first start using the WCF send adapter, but the constraint is by design in order to support transactional consistency within the message box.

Finally, send ports can be configured to route incoming fault messages (returned by the service) through traditional message box subscription techniques. You need to enable this functionality when desired.

Receive Adapter Architecture

The WCF receive adapter instantiates a single ServiceHost-derived class for each WCF receive location. 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). This includes the channel stack, dispatcher, and generic service instance. Almost all of the WCF adapters can be hosted within the BizTalk service process itself – the only exception is WCF-CustomIsolated, which must be used in a BizTalk isolated host by design. Even the HTTP adapters can be hosted in-process now.

Like send ports, receive ports are also message-type agnostic (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) into a common message type before publishing. 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 default behavior for the WCF receive adapter is to publish the first element found within the SOAP body, but you can tell it to only publish a specific element or the entire SOAP envelope if you wish. We’ll discuss how you configure message publishing options shortly.

Another important BizTalk design consideration is how most BizTalk adapters are designed to support acknowledgment messages (ACKs and NACKs), even for one-way receive ports, assuming of course the transport allows it. An acknowledgment message informs the caller that the message was received, which helps ensure transactional consistency within the message box. This BizTalk design characteristic implies that the WCF adapters will need to build on service contracts with request-reply operations.

In the following sections, we’ll go deeper into the design for the generic service contracts used by the WCF adapters, the generic service implementation, and the WCF configuration model.

Generic Service Contracts

The WCF adapters build the generic service contracts shown in Figure 12, which take into account the various BizTalk design considerations discussed in the previous section. There are a few additional service contracts I’ve left out for now that are used when transactions are required.

Figure 12: WCF Adapter Generic Service Contracts

// used only when the WCF adapter is configured with NetMsmqBinding

[ServiceContract(
    Namespace="http://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);
    void EndOneWayMethod(IAsyncResult result);
    ...
}
// used to model one-way ports that don’t use NetMsmqBinding (ACKs)
[ServiceContract(
    Namespace="http://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);
    void EndTwoWayMethod(IAsyncResult result);
    ...
}
// used to model two-way ports 
[ServiceContract(
    Namespace="http://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);
    Message EndTwoWayMethod(IAsyncResult result);
    ...
}

When you define a one-way WCF receive location that uses the NetMsmqBinding, the underlying WCF service will expose an endpoint using IOneWayAsync. If the receive location is not configured to use NetMsmqBinding, the underlying WCF service will expose an endpoint using ITwoWayAsyncVoid in order to remain compatible with the acknowledgment behavior. Otherwise, when you define a two-way WCF receive location, the underlying WCF service will expose an endpoint using ITwoWayASync.

IOneWayAsync 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.

A consequence of this design is that your WCF client applications cannot use service contracts with one-way operations to send messages to your WCF receive locations. The operations on the client-side contract should be annotated with IsOneWay=false and ReplyAction=”*”. The only exception is when you’re using NetMsmqBinding, in which case all operations on the client contract should be one-way.

One of the benefits of using generic service contracts (defined in terms of Message) is that it allows the WCF adapter to avoid the XML-to-object transformation process that occurs with typed contracts in general. The SOAP adapter implementation relies on such a mapping, which introduces unnecessary overhead and another potentially troublesome layer that doesn’t add additional value. There isn’t a good reason to use a .NET mapping since the WCF adapter only interacts with the message box and not with user-defined code where .NET objects might be easier to program against.

Another benefit related to using request-reply service contracts is that it allows the WCF receive adapter to return SOAP fault messages to the caller when errors occur within BizTalk Server. When you configure the WCF receive adapter, you can control whether it should include the exception details in the fault messages and whether the request message should be suspended within the message box on failure.

Generic Service Implementation

The WCF adapters come with a generic service class named BizTalkServiceInstance that implements all of the generic service contracts described in the previous section:

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

As you can see, BizTalkServiceInstance is configured as a singleton (InstanceContextMode.Single) and multi-threaded access is allowed (ConcurrencyMode.Multiple). Its primary responsibility is to decide how to publish the incoming WCF message to the message box, according to your configuration.

You can configure the WCF adapter to publish the entire SOAP message, the body of the SOAP message, or a particular XML element within the message (see Figure 13). The implementation of BizTalkServiceInstance uses the normal BizTalk Server publishing APIs to publish messages. This means messages will pass through the configured pipeline and the map collection before arriving at the message box. The WCF adapter doesn’t make any changes to the publishing process.

Figure 13: Receive Port Internals When Using the WCF Adapters
Bb967002.b7e5a217-2e2a-46c8-95a9-825285343370(en-US,BTS.10).gif

The WCF service isn’t performing any business logic – its only job is to publish messages to the message box. In BizTalk Server, you implement business logic within orchestrations that subscribe to the messages entering the message box.

BizTalk Server WCF Configuration

Another architectural difference is where the WCF configuration is stored. In typical WCF applications, it’s stored in application configuration files. BizTalk Server, however, stores adapter configuration information in the BizTalk SSO database since it may contain sensitive information like passwords. Hence, the WCF adapter configuration is also stored in the SSO database along with everything else. The WCF adapters come with some BizTalk-specific ServiceHost classes that know how to read the WCF configuration information from SSO during initialization.

The fact that WCF configuration information is stored in the BizTalk SSO database makes for a better management experience in general. For one thing, the WCF configuration information is stored in a central location as opposed to being scattered across numerous configuration files, and BizTalk Server provides nice tools for administrators to use. For example, the administration tools allow you to export application bindings, which in this case will include any WCF configuration. These binding files can then be imported to auto-configure applications with WCF send ports/receive locations, thereby simplifying deployment. This solution provides nice integration between the WCF and BizTalk Server configuration models.

One of the significant improvements in the new WCF adapters (compared to the previous SOAP and WSE adapters at least) is increased flexibility around hosting services. Many of the WCF adapters can now be hosted directly within the BizTalk service process (BtsNtSvc.exe), reducing the need for isolated hosts, although support for “isolated” hosting (e.g., IIS) is still fully supported with new tooling.

Hosting the WCF Adapters In-Process

All of the non-HTTP adapters listed in Figure 6 can be hosted within BtsNtSvc.exe – this includes the WCF-NetTcp, WCF-NetNamedPipe, WCF-NetMsmq, and WCF-Custom adapters, which I’ll refer to as the “in-process” adapters from now on. Although the administration tools force you to use WCF-BasicHttp and WCF-WSHttp in conjunction with an isolated host, you can work around this by defining a custom configuration (via WCF-Custom) that uses an HTTP binding in-process. The administration tools just encourage developers to use HTTP bindings in IIS, which is the general guidance from Microsoft.

A few examples of WCF bindings that can’t be hosted in-process include MsmqIntegrationBinding and the WSDualHttpBinding depending on the features you choose to use.

The WCF adapters create a ServiceHost-derived class for each receive location configured to use an in-process adapter. When you “enable” a WCF receive location, the adapter initializes and opens the ServiceHost and dynamically builds the WCF runtime components (see Figure 13). Ultimately, once you’ve enabled a WCF receive location, there will be a WCF service available for clients to call.

The ServiceHost life cycle is controlled by using traditional BizTalk Server techniques. You “enable” the receive location to initialize the ServiceHost and you “disable” it to dispose of the ServiceHost. Each adapter also provides a few settings that control ServiceHost open/close time-outs (e.g., how long it takes to call ServiceHost.Open and ServiceHost.Close respectively). You can also control general behaviors like service throttling (maximum concurrent calls) or the maximum incoming message size.

WCF-Custom can be used to define custom WCF configurations for send ports or receive locations (in other words, it provides both a send and a receive adapter), but on the receive side it’s only meant to be used in-process (within BtsNtSvc.exe). WCF-CustomIsolated, on the other hand, is only meant to be used in an isolated host, which implies it’s only a receive adapter (i.e., no send adapter functionality).

Generating “Metadata-Only” Endpoints

Since receive ports are untyped by nature, the in-process adapters do not enable metadata publishing (via HTTP GET request with “?wsdl”) or a WS-MetadataExchange (MEX). It’s possible to enable this functionality using the WCF-Custom adapter but the generated WSDL contract will be based on the generic service contracts discussed earlier (see "Generic Service Contracts"), which isn’t much help to WCF clients.

When you need to expose metadata for receive locations using the in-process WCF adapters, turn to the WCF Service Publishing Wizard. The WCF Service Publishing Wizard makes it possible to generate a metadata-only endpoint, hosted in IIS, describing the in-process WCF service.

When you run the wizard, you’ll specify the receive location you wish to expose along with the service contract details for the endpoint. The receive location specifies the address and binding details for the exposed endpoint, but you’ll have to supply additional information for the service contract. You can either point the wizard to a BizTalk orchestration from which it can derive the service contract or you can manually specify the service contract with schema definitions.

You launch the WCF Service Publishing Wizard from the Start menu or within Microsoft Visual Studio® 2005. The first decision you make (see Figure 14) is whether you want to create a new HTTP-based service endpoint (for an isolated host scenario) or a metadata-only endpoint (when using the in-process adapters). For in-process receive locations, you’ll want to select “Metadata only endpoint”.

Figure 14: Creating a Metadata-only Endpoint
Bb967002.dd21d3c2-010d-4f95-a859-eb720a0d19a9(en-US,BTS.10).gif

The next decision to make is what type of type information you’ll provide the wizard to produce the service contract for the endpoint (see Figure 15). You can provide either an orchestration or a custom service contract description that you’ll build manually. If you select the orchestration option, the wizard will derive the service contract from the port type and message types in use.

If you select “Publish schemas as WCF service”, you’ll have to use the tool shown in Figure 16 to build the service description manually. For this example, I’ve defined a service contract named BillingService that contains a single one-way operation named SubmitInvoice. The SubmitInvoice request message is mapped to the SubmitInvoice element found in my local schema definition.

Figure 15: Defining Metadata by Using a Schema
Bb967002.eb1c82d1-3a4a-4637-bb2d-a0e3a162da16(en-US,BTS.10).gif
Figure 16: Defining the Service Description
Bb967002.0e854134-e288-4a1a-ac5c-b4c89c5af549(en-US,BTS.10).gif

The next few steps of the wizard ask you to specify the target namespace for the metadata service and the IIS location where it should be published. When you finish the wizard, it generates the IIS virtual directory along with an .svc file, a web.config file, and supporting metadata files. Once the metadata endpoint has been published, you’ll be able to browse to it as shown in Figure 17.

Figure 17: Browsing to the Published Metadata
Bb967002.326db2a2-f39e-4057-9338-a8892a46bc2d(en-US,BTS.10).gif

The generated .svc file is mapped to a custom ServiceHostFactory called MexServiceHostFactory. The following shows the contents of BillingService.svc from the above example:

<%@ ServiceHost Language="c#" Factory="Microsoft.BizTalk.Adapter.Wcf.Metadata.MexServiceHostFactory, Microsoft.BizTalk.Adapter.Wcf.Runtime, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>


MexServiceHostFactory creates instances of MexServiceHost, which wraps BizTalkServiceInstance (notice the name of the service in Figure 17). The MexServiceHost instance only exposes a single MEX endpoint for metadata retrieval, which means you cannot invoke the actual service implementation through this ServiceHost – the sole purpose of this service is to supply metadata on behalf of the other WCF service hosted within BtsNtSvc.exe. That’s why it’s called a “metadata-only” service.

The generated web.config file contains some BizTalk-specific configuration information that you’ll want to be familiar with during the development process. You’ll find a section named <bizTalkSettings> that specifies the .svc-to-receive location mapping as well as other host-related settings (see Figure 18).

Figure 18: The Generated Configuration File (web.config)

<configuration>
  <bizTalkSettings>
    <mexServiceHostFactory debug="false">
      <receiveLocationMappings>
        <add markupFileName="BillingService.svc" 
          receiveLocationName="ReceiveViaWcfNetNamedPipe" 
          publicBaseAddress="http://server/" />
      </receiveLocationMappings>
    </mexServiceHostFactory>
    <webServiceHostFactory debug="false" />
    <isolatedReceiver disable="false" />
    <btsWsdlExporter disable="false" />
  </bizTalkSettings>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehaviorConfiguration">
          <serviceDebug httpHelpPageEnabled="true" 
            httpsHelpPageEnabled="false" 
            includeExceptionDetailInFaults="false" />
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service 
        name="Microsoft.BizTalk.Adapter.Wcf.Runtime.BizTalkServiceInstance" 
        behaviorConfiguration="ServiceBehaviorConfiguration">
        <endpoint name="HttpMexEndpoint" address="mex" 
          binding="mexHttpBinding" bindingConfiguration="" 
          contract="IMetadataExchange" />
        <!--<endpoint name="HttpsMexEndpoint" address="mex" 
          binding="mexHttpsBinding" bindingConfiguration="" 
          contract="IMetadataExchange" />-->
      </service>
    </services>
  </system.serviceModel>
  ...
</configuration>
...

Setting the disable attribute to “true” on <isolatedReceiver> allows you to test metadata exchange without having to set up the corresponding receive location. And setting the disable attribute to “true” on <btsWsdlExporter> removes the custom BtsWsdlExporter class from the service description and instead uses the generic service description. Setting the debug attributes to “true” will cause the debugger to launch when CreateServiceHost is called on the ServiceHost instance at run time.

The web.config file also contains a standard WCF service configuration for BizTalkServiceInstance. Notice in Figure 18, the <service> configuration contains a single MEX endpoint, although you can uncomment the second <endpoint> element if you also wish to support MEX over HTTPS. The service’s behavior configuration also enables the <serviceMetadata> behavior for HTTP GET retrieval.

Metadata-only endpoints are handy when you wish to simplify external integration with your receive locations using the in-process WCF adapters. As an alternative to generating metadata-only endpoints with the wizard, you can always produce the WCF metadata yourself (perhaps using SvcUtil.exe) and manually distribute it to the appropriate location for external consumption.

Hosting the WCF Adapters in IIS

The WCF-BasicHttp, WCF-WSHttp, and WCF-CustomIsolated adapters are, by design, meant to be hosted within IIS. When using one of these HTTP-based adapters, the adapter infrastructure loads in an “isolated” process. Isolated means a process external to the BizTalk service process (BtsNtSvc.exe) – in this case it’s the IIS process (W3WP.exe). All the BizTalk message processing occurs in the isolated process before the message is published to the BizTalk message box.

When you configure a receive location to use one of these adapters, you’ll have to perform a few extra steps to generate the necessary WCF code that will run in the IIS application domain. The WCF Service Publishing Wizard automates most of these steps for you through a sequence of dialog boxes.

Figure 19: Publishing a WCF Service Endpoint
Bb967002.a2f67e13-1630-4dbe-a021-6cc7a25f83d1(en-US,BTS.10).gif

When the wizard asks you what type of WCF service to publish, this time you want to select “Service endpoint” (see Figure 19) instead of “Metadata only endpoint”. Then you decide which WCF adapter to use with this external service endpoint – only the three adapters listed earlier are found in the adapter selection box. For this example, I’ve selected WCF-WSHttp. Notice you can also generate a metadata endpoint along with the service endpoint, and you can instruct the tool to automatically generate the BizTalk receive location corresponding to this new service endpoint.

The remaining steps in the wizard are very similar to what we walked through in the previous section for generating metadata-only endpoints. You can supply the service contract details through an orchestration or a user-defined service description based on schemas. Once you have completed the wizard, it generates the IIS application, the WCF configuration, and the corresponding receive location.

At this point you can return to the BizTalk Server Administration console and inspect the generated receive location. The receive location will be configured to use the WCF-WSHttp adapter – matching the adapter we chose in the wizard – and the receive handler is configured to use the BizTalkServerIsolatedHost (see Figure 20). The receive location will be configured to use the XMLReceive pipeline by default.

Figure 20: The Generated WCF Receive Location (WCF-WSHttp)
Bb967002.1df02411-f3bb-42f8-9410-8219107d5950(en-US,BTS.10).gif

If you check out the adapter configuration (by clicking Configure), you’ll see the endpoint address is configured with a path relative to the IIS application (see Figure 21). This address value is used to correlate between services running in an isolated host and the BizTalk receive location configuration. The isolated host will use the deployed service address to look-up the correct configuration at run time, when it initializes ServiceHost and the other BizTalk artifacts.

This means that all of the WCF configuration information still resides in the central BizTalk Management database, even when using HTTP-based adapters in an isolated host. The only thing that’s pushed into the IIS application is the service contract metadata information (in the form of XML Schema and service description XML files stored in App_Data). This is very different than the preceding Web service adapters (SOAP and WSE), which replicated much of the adapter configuration into the IIS application, thereby making those receive locations more difficult to manage and keep in sync.

The .svc file generated by the wizard in this case looks a little different than the last one. The following shows the contents of the BillingService.svc generated from the example above:

<%@ ServiceHost Language="c#" Factory="Microsoft.BizTalk.Adapter.Wcf.Runtime.WSHttpWebServiceHostFactory, Microsoft.BizTalk.Adapter.Wcf.Runtime, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>


Notice a different ServiceHostFactory is used this time – WSHttpWebServiceHostFactory – specific to the WCF adapter that we selected. When this factory creates ServiceHost instances, it initializes them with the endpoint configuration stored in the BizTalk Management database.

Figure 21: The WCF-WSHttp Adapter Configuration
Bb967002.718d0f0c-e9ed-4189-985d-f1c14c8ef434(en-US,BTS.10).gif

The generated web.config file will look similar to Figure 18 (especially since we asked the wizard to generate a metadata endpoint along with the service endpoint). The same <bizTalkSettings> and behavior configuration options are available to you in this case. The <webServiceHostFactory> element provides a debug attribute that breaks the debugger on the creation of the ServiceHost.

Although in this example we used the WCF Service Publishing Wizard to generate the IIS-hosted WCF service and the corresponding receive location, we could have also created the receive location first and then used the wizard to generate the WCF service. When taking this path, you simply need to ensure that the service address specified in the receive location matches that of the deployed WCF service.

Bb967002.note(en-US,BTS.10).gifNote
Windows Activation Services (WAS) hosting is not officially supported in this release. It may be possible to configure a WAS hosting using WCF-CustomIsolated but it’s not officially supported.

Command-Line Publishing Tool

It’s common for BizTalk Server developers to build automated scripts that simplify BizTalk Server deployment and management tasks throughout the enterprise. Hence, Microsoft has provided a command-line version of the BizTalk WCF Service Publishing Wizard, which you can use as follows:

BtsWcfServicePublishing PathName   [-AdapterName:value][-EnableMetadata][-ReceiveLocation][-Anonymous]  [-ApplicationName:value][-MetadataOnly][-MetadataReceiveLocationName:value]   [-MergePorts][-TargetNamespace:value][-Location:value][-Overwrite]

Figure 22 describes the command-line options shown above in more detail for your reference. You can download this tool from the BizTalk Server TechCenter (http://go.microsoft.com/fwlink/?LinkId=101820) on Microsoft TechNet.

Figure 22: Command-Line Publishing Tool Options

Command Option Description Type Default Value

AdapterName

Specify which adapter will be used for this Web service

String

WCF-WsHttp

(Allowed values include WCF-BasicHttp, WCF-WSHttp, and WCF- CustomIsolated)

EnableMetadata

Enables MEX for published Web service

Flag

False

ReceiveLocation

Create receive location in the specified application.

Flag

False

ApplicationName

Name of the BizTalk application in which to create receive locations.

String

Default BizTalk application

MetadataOnly

Publish a metadata-only endpoint

Flag

False

MetadataReceiveLocationName

Receive location that corresponds to metadata service

String

Null

PathName

Path and file name of BizTalk assembly (*.dll) or Web service description (*.xml) file.

String

<Default path in wizard>

TargetNamespace

Target namespace ofWweb service

String

http://tempuri.org/

Location

Location in which to publish. (Syntax: "http://host[:port]/path")

String

Automcatically generated based on project name

Overwrite

Overwrite (delete contents of) specified location

Flag

False

Anonymous

Allow anonymous access to Web service

Flag

False

MergePorts

Merge all operations in one port

Flag

False

There are several more advanced configuration options available when working with the WCF adapters in either send ports or receive locations. The following sections cover these options in more detail.

SOAP Action Header

Back in our first WCF send port example we specified a single action value for the entire send port (see Figure 8). When the target service exposes more than one operation, this send port configuration technique is not acceptable because each operation will require a different action value, so somehow the send port needs to figure out what action value to use at run time. Hence, the WCF send ports provided a way to accomplish this through a mapping between operation names and action values.

You specify the mapping in the text box provided for specifying the action value (in Figure 8), but instead of entering a single text value, you supply an XML element in the following format:

<BtsActionMapping>
  <Operation Name="SubmitInvoice" 
    Action="http://example.org/billing/IBillingService/SubmitInvoice"/>
  <Operation Name="CancelInvoice" 
    Action="http://example.org/billing/IBillingService/CancelInvoice"/>
</BtsActionMapping>


This example defines a mapping between two operations and their corresponding action values. You specify which operation you want the send port to use by setting the BTS.Operation message context property before the send port is activated – you could do this within an orchestration or a pipeline component. This process is automated when consuming services from within orchestrations.

Message Encoding

The WCF-BasicHttp and WCF-WSHttp adapters provide a configuration setting for changing the message encoding. You’ll find the encoding setting on the “Binding” tab for each of these adapters. The two options they provide are “Text” (the default) and “Mtom”. Both of these encodings are considered interoperable since they implement open standards and are widely supported. However, since the WCF binary encoding is specific to WCF, these adapters don’t make it possible to choose that encoding (although you can do so using the WCF-Custom adapter if needed).

MTOM, which stands for the Message Transmission Optimization Mechanism, is a good choice when you’re transmitting larger, binary payloads in your messages. MTOM builds on another specification, the XML-binary Optimized Packaging (XOP), to package binary elements in multi-part MIME messages. This creates numerous optimization opportunities for programming frameworks, like WCF, to capitalize on.

None of the in-process adapters make it possible to change the message encoding – since they aren’t designed for interoperability, they assume the binary encoding is the only logical choice.

Message Processing

All WCF receive adapters allow you to control how incoming SOAP messages will be published to the message box. Receive adapters are responsible for creating the BizTalk message (multi-part) consisting of a message context and a single body part. You can choose which node from the incoming SOAP envelope to use in the BizTalk message body. Figure 23 shows the options for controlling this setting.

You can choose to use the entire SOAP envelope, the body of the SOAP envelope, or a particular element within the SOAP envelope identified by an XPath expression. The default setting is “Body”, which means the first child of the <soap:Body> element will be used in the BizTalk message body.

Figure 23: Receive Adapter Message Processing Options
Bb967002.7456f8ff-c24c-4dc3-8127-a91a5528e962(en-US,BTS.10).gif

When you select “Envelope”, the entire <soap:Envelope> will be used within the BizTalk message body, which means the SOAP headers will be found within the BizTalk message body for future processing. However, if you are using the XmlDisassembler in your receive pipeline, it will actually strip everything from the SOAP message except for the first child of the <soap:Body> (similar to the “Body” option), thereby negating the “Envelope” behavior if that was the selected option. This behavior stems from the fact that the SOAP schema is registered with BizTalk Server as an “envelope” schema. Hence, you will want to ensure you’re using the PassThruReceive pipeline when selecting the Envelope option above.

The final option is to specify a node within the <soap:Body> to use within the BizTalk message body. You provide an XPath expression (in the “Body path expression” text box) to specify exactly which node to use. The expression is evaluated relative to the <soap:Body> element, which means an expression of “*” (short for “child:*”) identifies the children of <soap:Body>. If the expression selects more than one node, only the first selected node will be used. Also, another important point is that you can’t use XML namespace prefixes in the XPath expression. Instead, you’ll need to use full XPath expressions that test the local name and namespace values manually as illustrated in this example:

*/*[local-name()="invoice"]/*[local-name()="CustomerName"]

This XPath expression identifies the <CustomerName> element within <invoice>. Since BizTalk Server uses an optimized forward-only XPath reader to process these XPath expressions, you must ensure that your expressions only use forward axes (e.g., child, descendant, etc). You must avoid any axis that requires reverse navigation (e.g., preceding, preceding-sibling, ancestor, etc).

The node encoding controls how the node is processed after it has been selected. The available options include Xml, Base64, Hex, and String. The default is “Xml”, which means the XML representation of the selected node will be used in the message body. When the selected node doesn’t contain XML but rather some form of text, you specify what encoding should be used to extract the text. You can specify “String” if the node contains UTF-8 encoded text, or “Base64” or “Hex” if the node contains either form of encoded binary data. If the matched node doesn’t have data encoded as specified in the node encoding, an empty BizTalk message body is created by default. This general functionality is handy when you only want to publish the binary data found in a particular element to the message box.

There are similar messaging options when sending WCF messages from send ports, except that on the send-side you must specify how you wish to construct the SOAP message from the outbound BizTalk message. You can choose to use the body of the BizTalk message as the body of the <soap:Envelope> or you can provide an explicit XML template that specifies what should go in the <soap:Body> (see Figure 24).

Figure 24: Send Adapter Message Processing Options
Bb967002.4f6a686f-e676-4221-9523-3b2abce0e8e2(en-US,BTS.10).gif

Within the custom XML template, you use <bts-msg-body> to indicate where the BizTalk message body should go. The <bts-msg-body> element also has an “encoding” attribute that you can use to specify how the BizTalk message body should be encoded in the <soap:Body> element – the same encoding options exist here on the send-side: “xml”, “base64”, “hex”, or “string”.

So let’s assume that the outbound BizTalk message contains an <invoice> element but the target WCF service expects a <SubmitInvoice> element containing <invoice> as a child element. We can accommodate this scenario by specifying the following XML template in our send port configuration:

<SubmitInvoice xmlns="http://example.org/billing">
  <bts-msg-body 
    xmlns="http://www.microsoft.com/schemas/bts2007" encoding="xml"/>
</SubmitInvoice>


Notice in Figure 23 you also have the possibility to specify outbound message settings and in Figure 24 you can specify inbound message settings. These settings are enabled when working with two-way receive/send ports so you can also customize messaging behavior on the response side.

Error Handling

The WCF adapters provide a few settings that allow you to influence how errors (or SOAP faults) are handled by BizTalk Server. The WCF receive adapters provide two options on the “Messages” tab (see Figure 23). You can control whether or not inbound messages should be suspended when a failure occurs during inbound message processing. You can also choose to include exception details in SOAP faults returned to consumers – this corresponds to the <serviceDebug> behavior in WCF.

Send ports also provide a setting for controlling whether fault messages should be propagated to subscribing applications or if they should be suspended instead (see Figure 24). This setting is only available on solicit-response send ports since only those ports can return faults.

Otherwise the WCF adapters fit into the BizTalk error-handling architecture like any other adapter. For example, on send ports you can configure retry logic, a backup transport, and support for failed message routing to be used in conjunction with the WCF adapters.

Security

WCF provides numerous security options that differ across the various bindings, and you can take things even further via custom bindings. The purpose of this section is not to cover the details of the various WCF security features, but rather to show how the adapters surface those configuration settings.

Since the set of security options vary across the different WCF bindings, each WCF adapter only provides configuration options that are consistent with the underlying binding. Each of the WCF adapter configuration dialog boxes provides a “Security” tab, which surfaces the security options available for that particular adapter. Figure 25 shows the security options available when using the WCF-WSHttp adapter within a receive location, and Figure 26 shows the options when using it in a send port.

The main setting you choose is the WCF security mode – there are four options including “None”, “Message”, “Transport”, and “TransportWithMessageCredential”. The default security mode for the WCF-WSHttp binding is “Message” but for all the in-process adapters (WCF-NetTcp, WCF-NetNamedPipe, and WCF-NetMsmq) the default security mode is “Transport”.

Not all WCF adapters support all the different security modes. For example, the WCF-NetNamedPipe adapter only supports “Transport” or “None”. Also, the WCF-NetMsmq adapter only supports “Transport”, “Message”, or “Both”, which is a full combination of transport + message security.

When you select message or transport, you must specify the type of client credential to use. For message security the options include “None”, “Windows”, “Username”, and “Certificate”. When you choose anything but “Windows”, you must provide a service certificate allowing clients to authenticate the service. For transport security the client credential options include “None”, “Basic”, “Digest”, “Ntlm”, “Windows”, and “Certificate”.

With message security, you can also specify the algorithm suite to use for message encryption and key wrapping. And you can control whether the service credential is negotiated (as with Kerberos) or provisioned at the client (as with certificates) and whether a secure session should be established. These settings control whether WS-Trust and WS-SecureConversation are used within the channel stack.

Figure 25: WCF-WSHttp Security Configuration Options (Receive Location)
Bb967002.1bc5928e-8a6d-46a0-8b9a-e671a48bca98(en-US,BTS.10).gif
Figure 26: WCF-WSHttp Security Configuration Options (Send Port)
Bb967002.88f08d16-5a49-4aee-8cde-4391f5954cc1(en-US,BTS.10).gif

Most of the WCF receive adapters support SSO – simply select “Use Single Sign-On” to request an SSO ticket using the client credentials – check the documentation for details on which configurations do support SSO and which do not. When specifying “User name credentials” in the send port adapter configuration (see Figure 26), you can indicate you want to use SSO for the outbound credentials.

It’s also worth noting that when creating receive locations, you can specify the details of the published endpoint identity, such as the service principal name, user principal name, or certificate. Then, when creating send ports, you specify the “expected” service identity to use for authenticating the service.

Transactions

Some WCF bindings support flowing transactions within SOAP messages (see Figure 4). Hence, when using the corresponding WCF adapter, you can take advantage of this feature to flow transactions into BizTalk Server from a WCF client. You can configure one-way receive locations (using an appropriate WCF adapter) to flow transactions by checking the “Enable transactions” box on the “Binding” tab.

When a transaction flows into a receive location, it joins the transaction for publishing the message to the message box. This means that if the client aborts the transaction after having submitted a message to BizTalk Server through a transaction-enabled receive location, the message will never be written to the message box database, which means no subscriptions will fire. The message won’t be committed to the message box until the distributed transaction completes. This is why you can’t enable transactions on a request-response receive location – orchestrations can’t join the flowed transaction because they aren’t activated until the message box commits, hence, the transaction can’t span the response.

When you enable transactions on a one-way receive location, a different generic service contract is used by the BizTalkServiceInstance at run time – the contract is named ITwoWayAsyncVoidTxn:

[ServiceContract(
    Namespace="http://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);
    void EndTwoWayMethod(IAsyncResult result);
    ...
}


However, if the one-way receive location is configured to use the NetMsmqBinding, it actually uses a different variation named IoneWayAsyncTxn, but it’s essentially the same (ignoring IsOneWay).

Notice how the operations are annotated with the [TransactionFlow] attribute specifying that a flowed transaction is mandatory when using the operation. If you look at the definition of BizTalkServiceInstance, you’ll also see the [OperationBehavior] attribute on the implementation of each of these methods, specifying TransactionScopeRequire=true and TransactionAutoComplete=true. So, by checking “Enable transactions”, the WCF service will require a transaction to flow from the client.

Some of the WCF adapters allow you to choose which transaction protocol to use for “flowing” the transaction – the two options are “OleTransactions” and “WS-AtomicTransactions”. Use the former for better performance in Windows environments and the later in non-Windows environments.

You can also configure WCF send ports to flow transactions to external services. In this scenario, the message box transaction (for deleting the outbound message) is flowed to the external WCF service by using the transactional protocol you specify on the send port properties. Once the send port receives either an acknowledgment or response message, the transaction is committed. The default transaction time-out is 10 minutes by default, but you can configure this via MaxTimeout in machine.config.

Although the set of WCF adapters accommodate the most common WCF communication scenarios, you’re bound to run into situations where they don’t fit your exact needs. You may want to configure the WCF binding in a way that isn’t supported by the corresponding WCF adapter, or you may want to take advantage of a WCF extensibility component. It’s also possible you’ll need to consume WCF services that expose endpoints that aren’t callable by one of the predefined WCF adapters for some reason.

For all of these reasons, the suite of WCF adapters includes two special adapters – WCF-Custom and WCF-CustomIsolated – for defining custom WCF binding configurations. WCF-Custom is designed for in-process use while WCF-CustomIsolated is designed for use within an isolated host. This is the only significant difference between the two custom adapters, so the rest of this section focuses on using WCF-Custom. The same principles and techniques would also apply when using WCF-CustomIsolated.

Custom Bindings

You can create a custom binding configuration by choosing the WCF-Custom or WCF-CustomIsolated adapter and using the provided dialog boxes to specify the configuration. On the “Binding” tab, you can select the built-in binding you wish to configure and it will display its various configuration options.

When you do this you’re basically “taking the gloves off” to some degree, because it’s possible—perhaps somewhat easy—to configure yourself out of BizTalk Server product support by choosing an overall configuration that isn’t officially supported. The specific WCF adapters validate your configuration to ensure compatibility with BizTalk Server but these custom adapters do not. Let’s look at a simple example.

Earlier I mentioned how you can host HTTP endpoints within BtsNtSvc.exe by using WCF-Custom. You can accomplish this by creating a new receive location based on WCF-Custom. Then on the binding tab, you can choose one of the WCF HTTP bindings, such as “basicHttpBinding” for example. Once you’ve selected “basicHttpBinding”, you’ll be able to configure various aspects of that particular WCF binding (see Figure 27), including such things as the message encoding (text vs. MTOM) or security.

Once you’ve finished configuring the remaining WCF-Custom properties, you can enable this in-process receive location, which will host a service configured with a BasicHttpBinding endpoint.

You can also define completely new binding configurations by selecting CustomBinding for the “Binding Type” and adding in the various binding elements you wish to use. This really opens up the WCF extensibility model within the BizTalk WCF adapters. Using this technique, you really have full control over the final binding configuration because the built-in bindings constrain what you can configure to some degree. Figure 28 shows how to create a custom binding configuration that combines HTTP with the binary encoding – this is not possible with any of the built-in binding configurations.

Figure 27: Using WCF-Custom to Define a Custom Binding Configuration
Bb967002.91eda20e-f8ef-402e-b77e-b545f9fe5bd2(en-US,BTS.10).gif
Figure 28: Defining a New Custom Binding
Bb967002.8b99de20-ced6-4e97-9b31-60e907a06ee5(en-US,BTS.10).gif

Custom Behaviors

You can customize the set of service/endpoint behaviors used by the adapter at run time. The custom adapters provide a “Behavior” tab where you can configure the behavior settings. For example, if you want to enable metadata on a WCF receive location, you would have to create a custom behavior configuration by using WCF-Custom and add the ServiceMetadata behavior as illustrated in Figure 29. However, the published WSDL in this case will only represent the generic service contracts – you still need the WCF Service Publishing Wizard to produce “typed” metadata.

Figure 29: Defining a Custom Service Behavior
Bb967002.c8e4755c-fc42-4fae-a147-ba5690c4394f(en-US,BTS.10).gif

If you have custom WCF behaviors that perform business-specific tasks like validation, message logging/auditing, security checks, or tracking, you can enable them this same way. You just have to ensure the custom extensions are registered on each BizTalk Server machine during deployment.

Configuration Import/Export

When using WCF-Custom, you may want to import a WCF configuration from an existing configuration file in order to simplify or ensure the proper configuration. Or you may want to export a WCF-Custom configuration out to a WCF configuration file in order to simplify things on the WCF side. This is all made possible by the “Import/Export” tab made available by the WCF-Custom adapter.

When you import a WCF configuration, all of the WCF binding/behavior information will be automatically populated from the <system.serviceModel> configuration section. If the configuration file contains multiple endpoints, you will be prompted to choose the one you wish to import.

There are two aspects to working with the WCF adapters within orchestrations – you may want to consume external WCF services from within an orchestration or you may want to publish the orchestration itself as a WCF service. Both are supported by the new WCF adapters.

Consuming WCF Services Within Orchestrations

When you need to consume WCF services from within orchestrations, there are several BizTalk artifacts that you’re going to need, such as the schema definitions, port types, and binding information. In order to simplify producing these artifacts, the WCF adapters come with a WCF Service Consuming Wizard.

You launch this wizard within Visual Studio 2005 by using the “Add Generated Items” command. When you select “Add Generated Items”, you’ll see a “Consume WCF Service” template (see Figure 30). You launch the wizard by selecting the “Consume WCF Service” template and clicking Add. Then the wizard asks you to provide either a MEX endpoint (or “?wsdl” endpoint) or a set of local metadata files (e.g., XML Schema and WSDL). Figure 31 shows an example of using the wizard. Once the wizard has the metadata it needs and you instruct it to finish, it will generate the BizTalk artifacts necessary to use the service.

Figure 30: Add Generated Items
Bb967002.c543d811-edca-4c20-9f5b-499a0c8fbeef(en-US,BTS.10).gif

The wizard generates an orchestration file containing multi-part message types and port types that are compatible with the service, along with any required schema files. In addition, it provides binding files that you can use to import the correct port configuration for the target WCF service.

Publishing Orchestrations as WCF Services

You can also publish orchestrations as WCF services by using the WCF Service Publishing Wizard we covered earlier. The wizard generates the service contract based on the port type and message types in use within the orchestration and automates producing all of the WCF code you’ll need.

Putting the WCF wizard differences aside, working with WCF services within orchestrations is very similar to working with SOAP or WSE services in prior versions. You create Web ports based on the generated port types and connect Send/Receive shapes to them. In addition, you can process SOAP faults and when consuming WCF services and you can return SOAP faults to callers from an orchestration called as a service. The primary difference is how you interact with the adapter via the various message context properties made available during processing.

Programming WCF Adapter Headers

The WCF adapters define a new suite of message context properties that are used by the adapters at run time. You can use these properties to inspect headers or configuration information on incoming messages. Or you can use them to dynamically configure the WCF adapters on outbound messages.

The namespace is “http://schemas.microsoft.com/BizTalk/2006/01/Adapters/WCF-properties” for the WCF property schema. Figure 32 lists a few of the more common properties in the property schema, and there are many others. Say for example you want to specify the target address on a dynamic WCF send port. You can accomplish this by setting the “To” property in an Expression shape as follows:

outboundMessage(WCF.To) = "http://server/billingservice/billingservice.svc"

You can read incoming headers by using the InboundHeaders property and you can add custom headers to outbound messages by using the OutboundCustomHeaders property. These properties simply surface the raw XML for the header so you have to be ready to deal with it. The following example illustrates how to set the OutboundCustomHeaders property with a user-defined SOAP header:

outboundMessageInstance(WCF.OutboundCustomHeaders) = 
   "<headers><TrackingId>1983123</TrackingId></headers>"

Again, there are numerous WCF adapter properties that aren’t listed in Figure 32. See the MSDN documentation at http://go.microsoft.com/fwlink/?LinkId=92956 for complete reference information.

Figure 32: The WCF Property Schema

Name Description Promoted

Action

Operation name

Yes

To

WS-Addressing To header

Yes

ReplyToAddress

WS-Addressing ReplyTo header

Yes

FromAddress

WS-Addressing From header

Yes

InboundHeaders

All of the incoming headers (decrypted)

No

OutboundCustomHeaders

All outgoing headers

No

This final topic isn’t officially considered part of the WCF adapters, but it is another mechanism for bridging the gap between the worlds of BizTalk Server and WCF. As part of the R2 release, Microsoft has included new BAM interceptor components for WCF and Windows Workflow Foundation (WF) – these BAM interceptors can be used outside of BizTalk Server within traditional WCF/WF applications by simply modifying the application configuration. This makes it possible for WCF clients and services to capture BAM data, thereby integrating with the rest of the powerful BAM infrastructure you may be using throughout your system.

The WCF BAM interceptor is implemented as a custom endpoint behavior (BamEndpointBehavior) that you configure on client or service endpoints. In order to configure this behavior, you need to register it within the <behaviorExtensions> section of <system.serviceModel> as shown here:

...
<extensions> 
  <behaviorExtensions> 
    <add name="BamEndpointBehaviorExtension" type="Microsoft.BizTalk.Bam.Interceptors.Wcf.BamEndpointBehavior, Microsoft.BizTalk.Bam.Interceptors, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> 
  </behaviorExtensions> 
</extensions> 
...

With this in place, you can then define a new endpoint behavior configuration within the <behaviors> section. When you do so, you’ll specify the BAM datatabase connection string and polling interval:

...
<behaviors> 
  <endpointBehaviors> 
    <behavior name="bamBehavior"> 
      <BamEndpointBehaviorExtension primaryImportConnectionString="server=.;database=BAMPrimaryImport;trusted_connection=yes" pollingIntervalSec="5000" /> 
    </behavior> 
  </endpointBehaviors> 
</behaviors> 
...

Then you can enable the behavior configuration (“bamBehavior”) on any endpoint definition within your <service> configuration as illustrated here:

<configuration>
  <system.serviceModel>
    <services>
      <service name="BillingService">
        <endpoint address="http://server:8080/billing" 
                  binding="wsHttpBinding" 
                  contract="IBillingService"
                  behaviorConfiguration="bamBehavior"/>
        ...

These steps plug the BAM interceptor behavior into the WCF runtime. The behavior implementation injects message and parameter inspector components into the call execution path so it can track data before and after each call. You specify what you want to track through what’s called an interceptor configuration (IC) file. The following example shows the basic structure of an IC file:

<bam:InterceptorConfiguration xmlns:bam="..." xmlns:bamwf="...">   
  <bam:EventSource Manifest="IBillingService, BillingService, ..." 
                   Technology="WCF" Name="MyEventSource"/> 
  <bam:BamActivity Name="MyBamActivity">    
     ... // omitted for brevity
  </bam:BamActivity>
</bam:InterceptorConfiguration> 

As you can see, it’s just an XML file that describes what events (BAM activities) you want the interceptor to track. Once you have an IC file, you can deploy it to BAM by using the BAM deployment utility (bm.exe). You don’t have to modify or redeploy your WCF code to enable BAM tracking this way.

There are a few XML Schemas that describe the structure of IC files found in C:\Program Files\Microsoft BizTalk Server 2006\SDK\Samples\BAM\InterceptorXSDs. You can leverage these schemas to get XML IntelliSense® when authoring IC files in Visual Studio 2005 (simply copy them into C:\Program Files\Microsoft Visual Studio 8\Xml\Schemas). Unfortunately Microsoft hasn’t yet provided any additional tooling for working with IC files. The remaining details around IC files and how you author them is beyond the scope of this white paper. See the SDK samples for additional information.

Since the WCF BAM interceptor is an endpoint behavior, you can also enable it within the WCF adapters when using WCF-Custom or WCF-CustomIsolated (see the Custom Behaviors section above). One advantage to using the WCF interceptor (over the built-in pipeline interceptor) is that it can capture fault messages. Another potential advantage is consistency throughout your BizTalk Server and WCF applications.

The new WCF adapters in BizTalk Server 2006 R2 bring the flexibility of WCF communications to the world of BizTalk Server messaging. The WCF adapters make it possible to define send ports that consume a wide-range of external services and WCF receive locations that bring SOAP messages into the message box – these WCF services may be hosted in-process (BtsNtSvc.exe) or in an isolated host (IIS). The WCF adapters come with a few new tools – the WCF Service Publishing Wizard and the WCF Service Consuming Wizard – that make it easy to integrate the adapters with the rest of your application.

The WCF adapters provide a rich feature set, easily accessible through the WCF adapter configuration dialog boxes. They provide numerous options around message processing, security, transaction support, and error handling, which open new doors to new distributed integration scenarios that weren’t possible in the past. Plus, when the mainstream WCF adapters don’t fit your needs, you can always use the WCF-Custom or WCF-CustomIsolated adapters to define a custom configuration that does.

The WCF adapters mark an important milestone for BizTalk Server, one of maturity in today’s service-oriented landscape. As the product continues to evolve in the years ahead, you’re likely to see even deeper integration between WCF and the BizTalk Server product.

Aaron Skonnard is a cofounder of Pluralsight, a premier Microsoft .NET training provider. Aaron is the author of MSDN Magazine’s Service Station column, several popular XML books, and Pluralsight’s Applied Windows Communication Foundation, Applied BizTalk Server 2006, and Applied Web Services courses. Aaron has spent years developing courses, speaking at conferences, and teaching professional developers throughout the world. You can reach him at http://pluralsight.com/aaron.

Many thanks to Sarathy Sakshi, Jon Flanders, and Matt Milner for valuable feedback.

Was this page helpful?
(1500 characters remaining)
Thank you for your feedback
Show:
© 2014 Microsoft