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 .
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:
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:
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.
You should select the most appropriate binding based on your needs:
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.
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
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:
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.
Each contract was designed for a different scope (as suggested by their name):
[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); [OperationContract(IsOneWay = true, Action = "BizTalkSubmit")] void BizTalkSubmit(Message message); void EndOneWayMethod(IAsyncResult result); } [ServiceContract(Namespace = "http://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 = "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); [OperationContract(IsOneWay = false, Action = "BizTalkSubmit")] Message BizTalkSubmit(Message message); Message EndTwoWayMethod(IAsyncResult result); } [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); [OperationContract(IsOneWay = false, Action = "BizTalkSubmit")] void BizTalkSubmit(Message message); void EndTwoWayMethod(IAsyncResult result); } [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); [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:
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.
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.
The WCF Adapters provided by BizTalk correspond 1:1 to the most commonly used WCF bindings.
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:
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:
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.
I strongly suggest you to read the following whitepapers to have a better insight in WCF Adapters and their extensibility points.
Moreover, I recommend to download and review the following WCF Adapters samples on MSDN:
Hi Paolo! I wanted to expose an WCF Service (basicHTTPBinding) in BizTalk with two operations: one operation is Request-Response (Sync) and the other is OneWay (Async). The WCF Publishing Wizard accepts this configuration (a service with one operation async and the other operation sync) but it only creates a Receive Location related to a TwoWay Receive Port.
So my question is how to manage correctly the Async operation within the TwoWay Receive Port/Location created (a TwoWay Receive Location always wait for a response).
The only solution is to create two WCF Services? One with the OneWay operation and other with the TwoWay operation? I hope not.
Sorry if this question is not related directly to this blog entry but I couldn´t find a blog entry better to ask for your recomendation regarding this issue.
Regards,
Diego
Hi Diego,
that's allright, no worries. I tried to follow the steps you mentioned, and I used the BizTalk WCF Service Publishing Wizard to create a Receive Location with a Two-Way operation and a One-Way operation respectively. Then I looked at the artifacts generated by the Wizard, and indeed the latter created a single Request-Response Receive Port and a Request-Response WCF-BasicHttp Receive Location. Then I opened the WSDL of the generated service and indeed the service exposes 2 operations, both using the BasicHttpBinding_ITwoWayAsync service contract, which is not what you were expecting.
I'm afraid that in order to accomplish your objective, you have to create 2 separate Request Ports and 2 related Receive Locations, two-way and one-way respectively.
Note: beware that the service contract exposed by a One-way WCF-BasicHttp Receive Location is not the IOneWayAsync, as you could expect, but the ITwoWayAsyncVoid (see my article above). In other words, the operation exposed is not truly one-way, is just a two-way operationb with a void response. This deisgn was intentional, because one-way opeartions do not return any feedback or exception to the caller, and the architect that designed the WCF Adapter wanted to avoid this situation. The only Adapter using the IOneWayAsync and IOneWayAsyncTxn service contracts is the WCF-NetMsmq Adapter.
Ciao,
Paolo
Thanks for your time Paolo!
In my opinion, this (creating two web services to manage two operations) is a big restriction. For each similar requirement (mixed operations) the web services inventory will grow considerably. I hope that the WCF Adapter architect could find a solution to this in a future adapter version.
I already read your excellent article about the IOneWayAsync issue.
Thanks again!,