In any given integration project many different parties are involved. In some cases these parties have standard endpoints against which BizTalk operates and sometimes these endpoints are built as you go in the participating systems to meet a new demand. This is true for other types of projects as well – things get finished at different times – and you need to be able to work independent of each other during that time. What you often do determine very early in the project are the design of messages, schemas or APIs through which you exchange information. In many cases a BizTalk project can effectively use FILE send or receive ports that serve the same purpose as a One-Way send or receive port to say SAP would do at a later stage. But how about solicit-response send ports? What do you exchange these for?
In this post I’d like to introduce a way to handle solicit-response through the use of a catch all WCF Service. There any many ways in which to mock a service. The prime benefit with this approach is that you will be able to model your BizTalk solution the way you want it to be, without having to have access to the real service, and exchange the solicit-response port for it’s production or acceptance test counter parts at your convenience.
To achieve this we need something that let’s us send in any message, and based on some part of the message determine what message to send back, and the send it as a response.
WCF is a perfect candidate. It has functionality both to allow us to create methods that handles all incoming requests by specifying a wildcard (*) as the Action property, and accept any message and can send any message as a return. Using the Message base class it also allows us to easily create the response message, and populate the body of the message from the contents of a stream, such as a file (See the ‘Creating Messages from XmlReaders’ topic in the link).
So what I did was I created a WCF Service, and added a method to catch all messages:
[OperationContract(Action = “*“, ReplyAction=”*“)]Message CatchAll(Message message);
In the implementation for this method I have include the following code:
FileStream stream = new FileStream(ResponseHelper.GetResponseFile(requestAction), FileMode.Open);XmlDictionaryReader xdr = XmlDictionaryReader.CreateTextReader(stream, new XmlDictionaryReaderQuotas());MessageVersion ver = OperationContext.Current.IncomingMessageVersion;return Message.CreateMessage(ver, ResponseHelper.GetResponseAction(requestAction), xdr);
I have a small helper class that just helps me get data from the config, the config in turn looks like this:
type=”ServiceHost.RequestResponseHandlingConfigSection, ServiceHost“/></configSections><requestResponseHandling><actionList><add requestAction=”http://tempuri.org/IService1/GetData2”
This enables me to add new responses to incoming requests without needing to rebuild the service to incorporate a new response. You could go crazy here with code and undertakings to reply based on some context or what not. In the case presented here I’m just making it simple and returning the same static message for all request that matches a certain requestAction.
Finally, put this in the host of your choice. In my case I’ve got IIS so I’m hosting it there. That will also cause changes to the web.config to automatically get loaded, so that’s happy times.
Using this from a client is super easy. Just point the address of the client endpoint towards this service instead. The only thing that might not be super simple (though still fairly simple) is that you need to know what the meat of the response will look like when serialized as a response (the body of the response message). That is you need to Generate a sample response message from your wsdl.
Now let’s look at how we can utilize this to mock services in BizTalk Server. Oh, but wait, that sounds like it would be a bit of work to do, but… no, that isn’t the case. In fact, once you have configured the WCF service the only thing you need to do is to point your Send port at this service instead of the system that would otherwise be there in it’s place. Loop closed.