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:

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.

BizTalkWcfAdapterConfiguration

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.

BizTalkWcfHangingPort

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:

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.

Updating XSD file in InfoPath Form

Some time ago, I was asked to build a InfoPath form out of an Xsd file. I didn’t had any experience using InfoPath, but it turned out to be pretty easy.

Today, I was asked if I could modify the form in order to take in account some changes in the Xsd.

My first attempt was to have a look in the Data Source part of the Design Task pane of the designer. However, everything in there is grayed out, so there is no way to change the values there.

My second attempt was to naively try to open the .xsn file with a text editor to see what was inside it. The content is, as expected, unreadable.

Then I stumbled upon this InfoPath Help and How-to article: Extract or combine the form files for a form template. This was what I was looking for, as it was showing how to "disassemble" the form into pieces, modify some of the content then build the form back. This is done by right clicking on the "manifest.xsf" file in windows explorer then choosing the "Design" option.

InfoPathDesign

However, there is a catch. Simply replacing the old schema by the new one effectively changed in the Data Source part, but it was not automatically reflected in the form. InfoPath does not have a dynamic link to the Xsd file…

To reflect the new changes from the Xsd, you’ll have to delete the part that were changed in the form, and add them again on the form.

LINQ to SQL and auto increment fields

When using LINQ to SQL in Visual Studio 2005, Table and Column mapping has to be coded manually. This is not a very difficult job but it’s repetitive and boring (of course, if you are using Visual Studio 2008 to automatically generated the mapping code, this will be done automatically).

I ran into an issue while following a guide on manually map database tables to classes. When I tried to insert a new record, leaving the identity field empty in the object, I had the following error:

"Cannot insert explicit value for identity column in table ‘Contexts’ when IDENTITY_INSERT is set to OFF."

It was pretty obvious that, as the identity column was and Int32, it was set to 0 as default, and when LINQ tried to insert that row in the table the SQL Server raised an error as this auto incremented field cannot be explicitly set.

This is simply solved by using the IsDbGenerated attribute in the Column annotation description of the field, as shown in the following code.

private Int32 _id;

[Column(IsPrimaryKey = true, IsDbGenerated = true)]
public Int32 Id { get { return this._id; } set { this._id = value; } }

This attribute tells LINQ not to give a value for this field as it is generated by the database at insert time.

Another very nice thing about this is that once you have inserted the object in the database, this field will hold the value generated by the database. Practically, this means that after executing the following code

DataTable.InsertOnSubmit(obj);
DataContext.SubmitChanges();

the obj.Id property will contain the value that was assigned by the database.