BizTalk, WCF

BizTalk Send Ports, WS-Addressing, ClientVia and non-http prefixed To headers, Part 2

In a previous post I explained how we had a need to use the WS-Addressing To header to send a non-http prefixed URI, such as urn:company/path/subpath/Service1, and how that was supported, after a fashion, out of the box in BizTalk Server. It did however come with the limitation of not being able to edit the WCF config in the BizTalk Server Administration Console GUI once you loaded it from a binding file. I don’t like limitations.

In this post I’ll show you how you can create a very simple WCF behavior to help you to set a RemoteAddress EndpointAddress Uri to be able to accomplish the same thing, while still being able to continue to edit the port configuration.

WCF behaviors allows you to intercept and inspect or alter messages or metadata, or in other ways modify the runtime behavior or processing of the same as they are sent or received. In this case we are creating a client behavior.

The behavior is in essence very very simple, it’s only purpose is to alter the endpoint address at runtime. The place where I choose to implement this is in the ApplyClientBehavior method of the IEndpointBehavior interface.

void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint serviceEndpoint, ClientRuntime behavior)
{
    serviceEndpoint.Address = new System.ServiceModel.EndpointAddress(this.Uri);
}

Incidently, I borrowed this implementation with pride from the ClientVia behavior that comes with the .NET Framework. Apart from the fact that that behaviors sets the ClientRuntime.Via property and this sets the ServiceEndpoint.Address property the implementation is very close to exactly the same.

This allows you to configure BizTalk in the following manner.

The “Address (URI)” property can be set to anything (as long as it is http or https prefixed), since it will later be overridden.

image

In the behaviors section we now have two behaviors, clientVia:

image

and the new one I created, which I called remoteAddress:

image

clientVia is configured as the actual URI of the service we need to call, while the remoteAddress behaviors is configured with the value we want to have in the To header.

The solution contain three files of interest.

image

The App.config file holds a snippet of configuration that needs to be placed in machine.config or in the BizTalk WCF-Custom WCF extension part of the Send Handler of the host that handles the WCF calls being made. It exists to make the behavior available to the BizTalk process and looks like this:

<extensions>
  <behaviorExtensions>
    <add name="remoteAddress" type="bLogical.BizTalk.WSAHelper.RemoteAddressElement, bLogical.BizTalk.WSAHelper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3672865486d21857"/>
  </behaviorExtensions>
</extensions>

It points to the RemoteAddressElement class, whose responsibility it is to point out the type of the behavior and create new instances.

The RemoteAddressBehavior then in turn does the already above explained logic.

The project and code is available here.

I suppose a custom pipeline component setting the Address, or a Dynamic Send port for easier cases of configuration might also do the trick.

BizTalk, WCF

BizTalk Send Ports, WS-Addressing, ClientVia and non-http prefixed To headers

Through WS-Addressing services can require a certain value in the ws-addressing <wsa:to> SOAP header. WCF has full support for this. This support is inherited by the WCF-Adapters. When using WS-addressing in a BizTalk Server Send Port what you enter in the “Address (URI)” of the WCF adapters configuration will also be the value that ends up in the <to> header.

Like so:

image 

This will produce the following. Other headers and body removed for clarity.

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
  <s:Header>
    <a:To s:mustUnderstand="1">http://localhost:8990/Service1</a:To>
  </s:Header>
  <s:Body>
    ...
  </s:Body>
</s:Envelope>

If you need to have a different value in the <to> header than the actual address that the service is hosted at it becomes a little bit trickier. You need to use the WCF-Custom adapter and add the ClientVia behavior. The value configured as the “Address (URI)” will still end up as the value in the <to> header, but the actual URI that the call will be made to will be the value you configure in the ClientVia’s viaUri property.

Like so:

image image

This will produce the following (again cleaned for clarity):

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
  <s:Header>
    <a:To s:mustUnderstand="1">http://somedummyvalue/</a:To>
  </s:Header>
  <s:Body>
    ...
  </s:Body>
</s:Envelope>

Now, as long as the value that you want in the <to> header is http or https (depending on the bindings security settings) then you are fine. However, if you end up needing to have a value in your <to> header that looks for example like this: urn:company/path/subpath/Service1, then you’re in trouble.

You will get an error dialog saying that The specified address is invalid. Invalid address scheme; expecting “http” scheme.

image

Why? Because BizTalk Server in its diligence to help you configure things correctly will force you to enter an URI that is prefixed with either http or https (again, depending on the security setting of the binding). There is no way for you to configure a non-http prefixed port in the adapter GUI (that I know of).

A colleague of mine, Gustav Granlund, experienced this issue and found a solution: you can coup it in through a binding file, and the runtime will accept it. Doing this you can enter a “Address (URI)” like so:

image

And you are then able to send a message that looks like this (to an address of http://localhost:8990/Service1):

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
  <s:Header>
    <a:To s:mustUnderstand="1">urn:company/path/subpath/Service1</a:To>
  </s:Header>
  <s:Body>
    ...
  </s:Body>
</s:Envelope>

The caveat is that after having done this you cannot open and change WCF adapter settings in the port through the administration console GUI and keep the urn:company/path/subpath/service1 style URI. But, as mentioned, BizTalk will happily run with it. In a follow up post I examine another option.

HTH,

/Johan

BizTalk, SOAP, WCF

BizTalk and SOAP Fault version issues

A developer in the same team made me aware of an issue they were seeing where if the BizTalk Send Port returned an exception the Client that called the ReceivePort would get a response that was interpreted as null instead of as an exception.


Now this is a synchronous service call without any orchestration, where BizTalk is just a broker of the web service calls. What we want out of it is this:



  1. For exceptions throw by the backend service to get relayed back to the original caller.

  2. For no suspended messages to be visible in BizTalk when an exception occurs with the backend service – so that operations won’t be bothered with removing them.

  3. For operations to get notified of all other exceptions, ie suspended messages.

Now this is all quite easy, all you need to do is make sure the propagate fault flag is checked on the send port adapter settings:
image
(somewhat shortened dialog)


What can happen though is that when the SOAP version does not match between what the Send Port receives and relays and what the client that called the Receive Port/Location is expecting is that the Fault ends up not being correctly formatted and thus the client is unable to interpret it.


This happens when you use the BasicHttp adapter or BasicHttpBinding with the Custom Adapter on the Receive Port and NetTcp (or WSHttp or… etc) on the Send Port (or vice versa). It happens because the SOAP version that BasicHttp uses is different than that used by the other WCF Adapters.


A sample SOAP 1.1 Fault look like this:

<s:Fault>
<faultcode>s:Client</faultcode>
<faultstring xml:lang=”sv-SE”>You entered 666</faultstring>
</s:Fault>

(where the namespace s is defined on the envelope and points to xmlns:s=”http://schemas.xmlsoap.org/soap/envelope/&#8221;)


While a sample SOAP 1.2 Fault look like this:

<s:Fault xmlns:s=”http://www.w3.org/2003/05/soap-envelope”>
<s:Code>
<s:Value>s:Sender</s:Value>
</s:Code>
<s:Reason>
<s:Text xml:lang=”sv-SE”>You entered 666</s:Text>
</s:Reason>
</s:Fault>

In our scenario, with the type of metadata that BizTalk exposes for the service, what happens at the client is that what is actually a Fault instead gets interpreted as a valid response, but since the element that represents the response, let’s call it GetDataResponse just for sake of illustration, is missing – the client will interpret it as a null response. Highly unwanted.


The solution is to make sure that the Fault response is valid for the version of SOAP used by the receive side adapter, that is; do a transformation. A transformation can be done in many places: a map, a pipeline component, a WCF Message Inspector. In my case I prefer to place the component resolving the problem as close as possible to the thing causing the problem – which here means I opt for the Message Inspector, but a map might be the easiest for many. I might add the implementation of the message inspector in a later post, but for now, below is some custom xslt you can use in a map (or elsewhere) (if you do not use custom xslt you might get complaints from the client that the namespace prefixes are incorrect for reserved namespaces) – it maps from SOAP 1.1 to SOAP 1.2 (from BasicHttp to others, like NetTcp). You might perhaps also have to map in the other direction.

<xsl:stylesheet xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”
xmlns:msxsl=”urn:schemas-microsoft-com:xslt”
xmlns:var=”http://schemas.microsoft.com/BizTalk/2003/var”
exclude-result-prefixes=”msxsl var s0″ version=”1.0″
xmlns:s0=”http://schemas.xmlsoap.org/soap/envelope/”
xmlns:xml=”http://www.w3.org/XML/1998/namespace”
xmlns:s=”http://www.w3.org/2003/05/soap-envelope”>
<xsl:output omit-xml-declaration=”yes” method=”xml” version=”1.0″ />
<xsl:template match=”/”>
<xsl:apply-templates select=”/s0:Fault” />
</xsl:template>
<xsl:template match=”/s0:Fault”>
<s:Fault>
<s:Code>
<s:Value>
<xsl:value-of select=”faultcode/text()” />
</s:Value>
</s:Code>
<s:Reason>
<s:Text xml:lang=”sv-se”>
<xsl:value-of select=”faultstring/text()” />
</s:Text>
</s:Reason>
<xsl:if test=”faultactor”>
<s:Role>
<xsl:value-of select=”faultactor/text()” />
</s:Role>
</xsl:if>
<xsl:for-each select=”detail”>
<s:Detail>
<xsl:value-of select=”./text()” />
</s:Detail>
</xsl:for-each>
</s:Fault>
</xsl:template>
</xsl:stylesheet>

.NET 3.5, BizTalk Server 2009, Development, SOA, WCF

Oh BizTalk, why dost thou mock me?

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:

<configSections>
  <section name=”requestResponseHandling
type=”ServiceHost.RequestResponseHandlingConfigSection, ServiceHost“/>
</configSections>
<requestResponseHandling>
  <actionList>
    <add requestAction=”http://tempuri.org/IService1/GetData2
responseAction=”http://tempuri.org/IService1/GetData2Response
responseLocation=”GetData2Response.xml” />
  </actionList>
</requestResponseHandling>

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.

.NET 3.5, WCF

Contruct ChannelFactory takes too long with config

Recently we experienced an issue with a service where the first call took a long time to complete. Subsequent calls would complete fine and fast, but the first call took a long time. Using Service Trace Viewer told us that the problem lay at constructing ChannelFactory.


image


The detailed trace of this activity didn’t give us any more hints to what was causing the problem.


image


All we could see was that the time appeared to all disappear when WCF tries to get the configuration for service.


The code for this (I’m just using the automatically generated Service1 template to illustrate) was as follows:

proxy = new Service1Client();
Console.WriteLine(proxy.GetData(22));

This is strange indeeded. Since loading the config seemed to be the issue, we changed the code to do this programmatically instead.

EndpointAddress address = new EndpointAddress(“net.tcp://localhost/SimpleService/Service1“);
proxy = ChannelFactory<IService1>.CreateChannel(new NetTcpBinding(), address);

Running this and looking at the trace for this revealed that this was a much more performant way of doing this.


image


For the scenario we had this solution was fine – but it’s not really a solution, it’s a workaround.


I’m still at a loss to describe why this happened on these servers, since the same thing worked quite differently on other servers. There, both solutions performed the same. So this is obviously something connected to some setting or circumstance that differs on those servers when compared to others.


If anyone has insight into this, or suggestions, please share.