Next week I will be doing a talk on Windows Azure BizTalk Services with regards on how one can add BAM functionality. During this talk a demo will be the ‘Pièce de résistance’. this demo is based on an article I have written earlier and which can be found on TechNet. Well to cut to the chase… I would not be who I am if I would have not taken this article to the next level and while doing so I encountered a nice challenge.
In my demo there is a scenario in which I have a custom MessageInspector which can be configured as such that it can deliver messages to either a Servicebus Queue/Topic/Relay or BizTalk Service Bridge endpoint. While testing the various scenario's I encountered a particular issue when I tried to send a message to another bridge. The error message which was 'reported back stated'
Component xpathExtractor. Pipeline Runtime Error Microsoft.ApplicationServer.Integration.Pipeline.PipelineException: An error occurred while parsing EntityName. Line 5, position 99.
at Microsoft.ApplicationServer.Integration.Pipeline.Activities.XmlActivitiesExceptionHelper.Throw(String message, XmlActivityErrorCode errorCode, String activityName, String stageName, IEnumerable`1 messageProperties)
The above mentioned error was caused by the error-message which was sent back and caused a failure which I could not easily debug any further without a complete rewrite. While I had no time for this I decided to use a different approach in sending the messages. Up to that point I used the WebClient class in combination with the UploadDataAsync Method but I decided to give the OpenWrite method a go. This decision proved to be very useful as my existing exception-handling was not able 'kick in' without causing the parent TASK to go in to a faulted state. Thus by using the OpenWrite method I was able to extract he 'real' exception. This exception message stated:
"The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel." "The remote certificate is invalid according to the validation procedure."
At that point I reached the Eureka moment and it all started to make sense. It all boils down to the fact that for development/test purposes we all use a self-signed certificate (created for us when we provisioned out Windows Azure BizTalk Service). This certificate is installed on our client machines, thus allowing us to make requests to the Windows Azure BizTalk Service. This explained why my test-console application did not throw any exceptions when calling the Windows Azure BizTalk Service Bridge in question. However when this code is invoked from within the message inspector which is hosted in Windows Azure.' it runs into the fact that 'there is a problem with the security certificate', this makes sense as it is a self-signed certificate.
So now that I figured out the why, I needed a way to tell my code to ignore these kind of warning when encountered. Well luckily for is, this little gem is available and can be found in the System.Net.ServicePointManager class. This gem is called ServerCertificateValidationCallBack. This CallBack will return false in case the Server Certificate is not complying with the policies (in our case, it is by default not trusted as it is self-signed), so all we need to do is ensure that it always returns true and thus ignoring the security check
please do not do this in production environments! You otherwise might be ending up sending data to a not trusted source (i.e spoofed server etc.)
Below I added the piece of code which implements the ssl validation-check bypass:
using (var client = new WebClient())
{
Uri EndPointAddress = new Uri(this.Endpoint);
//Add WRAP ACCESS TOKEN
client.Headers[HttpRequestHeader.Authorization] = String.Format("WRAP access_token="{0}"", this.AcsToken);
//Add Content Type
client.Headers["Content-Type"] = "application/xml";
//Publish
try
{
//The 'GEM' Ignore validation callback which cause an error
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
using (var stream = client.OpenWrite(EndPointAddress, "POST"))
{
byte[] data = System.Text.Encoding.UTF8.GetBytes(messagePayload);
stream.Write(data, 0, data.Length);
}
}
catch (System.Net.WebException wex)
{
AppendExceptionsToLog(wex);
}
catch (ArgumentNullException anex)
{
AppendExceptionsToLog(anex);
}
catch (Exception ex)
{
AppendExceptionsToLog(ex);
}
}
Cheers and hope to see you soon! Especially if you are going to attend the BizTalk Summit 2014 in London this March, don't hesitate to say Hi :-)