There are quite a few posts on different blogs that explain how to consume and expose REST services from BizTalk that are really good (this
one from Mikael Håkansson about the bLogical REST Start Kit for BizTalk, or
this series from Steef-Jan Wiggers about the new REST features in BizTalk 2013), but I thought that there has always been a missing piece in the picture: How to handle errors when BizTalk acts as a consumer of REST services.
When we consume a REST service, likewise when we access any web resource in or browser of choice, there are chances that we will face scenarios where we won’t be receiving the happy “OK” HTTP result (HTTP Status code 200), but some other Status Code letting
us know that something went wrong. It could be either an specific error scenario defined in the API (e.g. an “Bad Request” HTTP Status code 400 caused because of a misuse of the API), the actual REST resource not existing on the target service (HTTP Status
code 404, Not Found) or even a full melt-down of the service caused by an unhandled exception (most probably an HTTP status code 500).
It all depends on the specific design and implementation of the REST API, as there are many different “ideological movements” on how some HTTP codes should be used in a REST API. I won´t get into that swampy territory, and we will just accept the fact that
at some point we can face those non-200 status codes :D
The main issue with BizTalk, that looks like is still the same with BizTalk 2013 and its new WCF-WebHttp adapter, is that those non-200 HTTP codes are not available on the response message to a REST call when they happen. We might want to make our solution
to be able to react to those scenarios and take the corresponding actions (e.g. creating a fault message related to that failure so the operations team can be aware of it and so correct the issue).
In this post we will take a look into how we can remediate this for both BizTalk 2010 (when using the REST Starter Kit approach to call a REST service) and BizTalk 2013 (using the WCF-WebHttp adapter).
The first step we will take will be to download and install the bLogical REST Starter Kit for BizTalk, which can be downloaded from codeplex
http://biztalkrest.codeplex.com/. We will use it as a base to consume REST services from BizTalk 2010.
Once it´s all setup, we will modify the sample REST service provided with it for testing. We will just simply return a 400 HTTP Status code as a result if the inbound request ID is different from “123”.
With this we will be able to force that 400 result scenario by just modifying the inbound test message provided with the samples:
If we drop that modified message to the inbound file drop, the web service will return the 400 Status Code as a result, and both the Send port and Orchestration service instances get suspended:
OK, so that result could be expected from a WCF point of view. A
ProtocolException is received by the consumer (BizTalk in our case), and the inner exception is a
WebException that specifies the Status Code received (400). This should be easy then…
We are so happy with our finding that we go straight into the sample ConsumeGET.odx orchestration included in the REST Start Kit for BizTalk and add some exception handling around the interaction with the REST service.
We just add the corresponding exception handling scope and few variables to get the inner WebException and the Status code received from the service.
Build, deploy, test…. And fail :(
We see that the Orchestration is suspended again with the following error:
And that’s the key of it. The WCF adapter just gets the information form the protocolException received and puts it into a XlangSoapException, so we cannot correctly access the information we want. At least not in an appropriate way (I’m not going to start
mangling around with the XlangSoapException message text to get the HTTP Status code from there :D).
What we need to do here is to get a hook into the exception right before BizTalk jumps in and transforms it into an XlangSoapException.
What we will do for this is create a custom binding element, that in turn will create the corresponding WCF channel to handle the interaction with the service, so once the ProtocolException comes, we can play with it. Might sound a bit complex, but as you
will see is simpler that it looks.
All the code for that is included in
this sample in MSDN.
Basically we have four classes involved:
We will also create a Property Schema (in the corresponding BizTalk project) that will allow us to retrieve the message header from the message contexts once it arrives to the orchestration.
Finally we will just need to deploy the projects (the WCF extension assembly into the GAC and the Schemas project into BizTalk) and modify the machine.config file so BizTalk is aware of our new binding element extension:
"adrb.CustomWebHttpBinding.WebRequestInterceptorBindingExtensionElement, adrb.CustomWebHttpBinding, Version=126.96.36.199, Culture=neutral, PublicKeyToken=0b236f220eb351a7"
In order to test this solution, we will modify the sample ConsumeGET.odx orchestration include in the bLogical REST Start Kit for BizTalk to check for the existence of that custom WCF message header we add when a ProtocolException happens and capture the
status code from it. We need to add a reference to the schemas project (adrb.Schemas) where the property schema was created to define the message header context property.
We will just retrieve the WCF header from the message context of the response message we will receive (that in case of a service failure will be the custom fault message we create in the channel), get the status code from it and suspend the orchestration
(but we could be creating a ESB Toolkit fault message that mentions the status code, trace the information in our logs…)
Finally, we need to modify the Send port used in the sample solution to interact with the web services so it uses out custom binding element. I added a binding file into the solution to make it easier for you to apply the configuration, but basically the
changes to make are:
After all that, we are ready to test the solution. We just need to drop the test message that makes the sample REST service a HTTP 400 status code and see how our orchestration instance gets suspended telling us the HTTP Status code that was received from
the service. We achieved our goal of being able to effectively retrieve the HTTP status code and so be able to use it in our code
After consuming the same test service we used above by following the good guide put together by Richard Seroter
here on how to use the new WCF-WebHttp adapter that comes with BizTalk 2013, it looks like the XlangSoapException behavior we observed before is still the same in BizTalk 2013, so initially
the same customBinding approach followed with BizTalk 2010 would apply here. In any case I didn't have time yet to explore any other possible alternatives in BizTalk 2013, but I guess we won't be very lucky...
Read suggested related topics:
Another important place to find a huge amount of BizTalk related articles is the TechNet Wiki itself. The best entry point is
BizTalk Server Resources on the TechNet Wiki.