Calling One Way WCF Service with BizTalk WCF Adapter, Part 2
As promised, here is the follow up of my previous post: Calling One Way WCF Service with BizTalk WCF Adapter, Part 1.
Let’s do a qui recap: we want to create a WCF proxy that will call a one way web service and return an empty message to BizTalk so the messaging process doesn’t timeout waiting for an answer.
The Interface
The first step is to create a service interface that is able to receive any message. This is done by
[ServiceContract(Namespace = "http://pvle.be/WcfOneWayProxy", Name = "OneWayProxy")] public interface IOneWayProxy { [OperationContract(Action = "*", ReplyAction = "*")] Message ProcessOneWayMessage(Message message); }
The operation has to be defined as a request/reply operation, as this is what BizTalk expects. Note the Action property of the OperationContractAttribute, its value is set to "*" meaning that all received messages will be dispatched to that operation.
The Implementation
Now that the interface is ready, let’s implement it.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ValidateMustUnderstand = false)] public class OneWayProxy : IOneWayProxy { private const String ConfigurationName = "ServiceEndpoint"; private static ChannelFactory<IOutputChannel> Factory; static OneWayProxy() { BasicHttpBinding binding = new BasicHttpBinding(); OneWayProxy.Factory = new ChannelFactory<IOutputChannel>(OneWayProxy.ConfigurationName); OneWayProxy.Factory.Open(); } #region IOneWayProxy Members public Message ProcessOneWayMessage(Message message) { IOutputChannel channel = OneWayProxy.Factory.CreateChannel(); try { //Send the one way message channel.Open(); channel.Send(message); channel.Close(); } catch (Exception) { //Do something, log the exception, whatever return Message.CreateMessage(message.Version, "http://pvle.be/EmptyReplyAction"); } //Whatever happens, send a response as this was "Fire and Forget" for the caller //Empty response send back to BizTalk so messaging process can terminate gracefully return Message.CreateMessage(message.Version, "http://pvle.be/EmptyReplyAction"); } #endregion }
A couple of remarks here:
- You need to have a valid client endpoint configuration in you App.config/Web.config that has the name defined in the ConfigurationName const.
- To create the message that is to be returned, we use the received message’s Version property, ensuring that there is no version mismatch.
Now that we have our service implementation, we can host it. I hosted it in IIS, as this is probably the best way to host WCF services and as this proxy should be running all the time.
BizTalk WCF Adapter Configuration
The last step is to make sure that your one way WCF adapter is calling the proxy. This is done by changing the address in the WCF Adapter configuration in your BizTalk project.
Once this is set (the SOAP Action header remains the same), you are ready to run you orchestration. You will see that the messaging process will no longer timeout, as our home made proxy will send an empty response message.
Improvements
Let’s face it, this implementation is fine for a proof of concept, but it’s hardly enough for a real application as only one endpoint is defined in the configuration.
If you have multiple one way endpoints and you want to reuse that proxy, you’ll probably need to have some lookup table in the proxy code to define the destination of the call, based on the To property of the Message object. This way, you can use a single one way proxy for all the actions needed in your orchestrations, as long as you are not using the same action for more than one endpoint.
Calling One Way WCF Service with BizTalk WCF Adapter, Part 1
If you ever tried to call a One Way web service operation with BizTalk, you might have read that BizTalk’s WCF Adapters don’t support One Way calls. The orchestration calls the service as expected and carries on running, but some Messaging process still hangs in the BizTalk Server Administration Console. Simply put: BizTalk 2006 R2 WCF Adapters don’t support "Fire and Forget" communication pattern (message is sent and reception is acknowledged by the listening service, but no response is sent back).
In the "Using the Windows Communication Foundation (WCF) Adapters in BizTalk Server" paper by Aaron Skonnard, it is clearly stated at page 22:
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.
This means that if an orchestration calls a service operation marked as One Way (hence not returning anything), the orchestration will continue and terminate fine, but the port that called the service will hang there for a response.
With default settings, the process will try to call the service three more times before giving up raising some CommunicationException:
System.ServiceModel.CommunicationException: The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error.
This is not very nice.
This issues has been discussed many times on blogs. One of the solution proposed by Sonu Arora is to remove the IsOneWay operation attribute at the service, so the service sends an empty SOAP message as a response. This is the same solution that what is advised by Aaron. However, this means that you have some control on the service itself, which might not be the case. On top of this, if you have other client calling that service, should they all change because of BizTalk? I don’t think so.
An other solution proposed by Josh Twist, who’s encountering the same issue but the other way round, is to either modify the orchestration (hence making it aware of the post used, which is not good), or to build an intermediary service that will support the One Way operation (whichever direction you choose) and adapt to make sure BizTalk gets what it needs.
This is what I did and I will explain it is part 2 of this post, as I’m running out of time today
BizTalk complaining about Orchestration instances still existing
As I was studying BizTalk 2006 R2, I came across a strange error. This error was reported by Visual Studio 2005 when trying to redeploy.
Could not change the bindings for orchestration ‘xxx’, Version=1.0.0.0,Culture=neutral, PublicKeyToken=c380e04620d206e8′ as one or more instances of the orchestration still exist.
Trying to act on the orchestration itself or even the solution in BizTalk Administration Tool was giving the same error.
The fix was found in this blog post: One or more instances of the orchestration still exist.
So, there are two solutions to fix this issue:
- Terminate instances manually using the BizTalk Administration Tool, which didn’t work for me.
- Use a stored procedure to clear BizTalk’s message box of all messages. This one didn’t work either.
As pointed out in one of the comments of the abode post, the bts_CleanupMsgbox comes empty at BizTalk install. This means that it executes when you call it, but nothing happens. The orchestrations were still in the list of running orchestrations in BizTalk Administration Tool.
However, the script to create the working procedure is located in the "C:\Program Files\Microsoft BizTalk Server 2006\Schema\msgbox_cleanup_logic.sql" file. Once this has been executed, the stored procedure will correctly clean BizTalk’s messages database.
