Archive for April, 2008

Using BAM for latency tracking in a BizTalk request response scenario

Monday, April 28th, 2008

This post will try and explain how BAM tracking can be used in SOAP based request response scenario in BizTalk 2006. It important to notice that some of the issues discussed in the post are specific to the SOAP adapter and are non-issues if the scenario would for example use the the WCF adapter or similar.

Describing the scenario

In this case we have a SOAP receive port that receives a request and returns a response. The request is routed to a orchestration that calls three different send ports. These ports then sends new requests to back-end systems and returns responses (communication with back-ends systems are also SOAP based). The three responses are used to build up the final response that is then returned to original receive port as a final response.

Our goal is to track the duration between the request and response on each of the ports. The idea is also to find a solution and tracking model that doesn’t have to change if we add or remove ports or add similar processes to track.

scenario

Defining and deploying the tracking model

We’ll start by defining our tracking model in Excel. Our activity contains of the following items:

  • InterchangeId (data item)
    As we won’t correlate all the tracking point into one single row (that would break the goal of having one model for all processes, the model would then have to be specific for one process and it’s specific ports) the interchange id will then tell us what different rows belong together and that describes one process.
  • ReceivePortName (data item)
    The name of the receive port.
  • Request (milestone item)
    The time the request was either sent or received (depending on if we track a port that received/sent the request using a receive port or send port).
  • Response (milestone item)
    The time the response was either sent or received (depending on if we track a port that received/sent it’s response on a receive port or send port).
  • SendPortName (data item)
    The name of the send port.

After we described the model it’s time to export it to an XML representation and then to use the BM tool to deploy it and generate the BAM database infrastructure. You’ll find some nice info on this here.

Using the Tracking Profile Editor to bind the model

Next step is to bind the model to the implementation using the Tracking Profile Editor. The figure below shows the different properties that were used. Notice that none of the items was bound to the actual orchestration context. All properties are general properties that we track on the ports. This is important as that gives us the possibility to just add and remove ports to change the tracking.

tracking profile using continuation

The next figure shows how the tracking of the request milestone event actually happens on either the RP1 port or on any of the three different send ports! If we developed a new process using other ports we could just add it here, no new model required.

tracking profile configure ports 2

What about the continuation then?

Our final problem is that unless we somehow correlate our request tracking point with our receive tracking point the receive we’ll end up with each tracking point spread over several different rows. In the example below I’ve marked the request for the RP01 port and the response event on the same port.

bam portal split results

The reason for this is of course that BAM doesn’t have a context for the two tracking points and doesn’t know that actually belongs together. This differs from tracking in a orchestration were we always are in a context (the context of the orchestration), it’s then easy for BAM to understand that we like to view all the tracking point as one row – when tracking on ports it’s different. Continuation helps us tell BAM that we like have a context and correlate these two points.

tracking profile using continuation 2

In our case ServiceID is the prefect candidate for correlating the two points. A request and a response will have the same service id. In an other situation we could just as well have used a value from inside the message (say for example an invoice id).

The result is one single row for the request response for each port. So in our case a complete process (a complete interchange) is shown on four rows (one row for each of the ports). In the example below the first rows shows us the complete duration (and the other tracking data) between the request response to the client. The other rows show the duration for the send ports communication with the back-ends systems.

bam portal complete results

This model might not be optimal in an other scenario where your process are more fixed and you can then create a tracking model that is more specific to you actual process. But this solution meets our design goal as we’re now able to just add and remove port using the tracking profiler to track new port in completely new processes without having to go back and change the tracking model.

note  NOTE: When configuring BAM to track a port the MessageType is actually promoted. This causes some problems in combination with the SOAP based ports that have been published using the Web Services Publishing Wizard. Saravana writes about this here and all his articles on this subject is a must read when working with SOAP ports. The problem however comes down to that the Web Services Publishing Wizard generates code that puts the wrong DocumentSpecName in the message context and that causes the XmlDisassembler to fail (it tricks the XmlDisassembler to look for a MessageType that doesn’t exists).

This usually isn’t a problem (unless you like to use a map on a port) but as BAM will force the port to promote the MessageType based on the DocumentSpecName we’ll have to fix this. Saravana has two solutions to the problem and I find the one that replaces the DocumentSpecName with a null value and lets the XmlDisassembler find the MessageType to work well.

Speaking at Developer Summit on Masterdata Management using BizTalk 2006

Thursday, April 24th, 2008

I recently spoke at the leading developer conference here in Sweden called Developer Summit. The talk was called Masterdata Management using BizTalk 2006. The slides can be found here.

I can really recommend Developer Summit as a conference. Everything is super well organized and having the opportunity to listen to celebrities like David Chappell, Jim Webber, Dan North and Christian Weyer in Sweden is really great!

This year I also liked the mix of presentation as some where more general presentation as for example  Benjamin Ling who’s the director of platform at Facebook and who gave an insight to how the platform is managed and developed. I also really enjoyed (besides the obvious ones as for example Christian Weyer’s WCF talk) Frans Hänel’s talk on the history and architecture behind a major price comparison site called prisjakt.nu - very interesting and a great technical mix in otherwise Microsoft focused conference.

Writing BizTalk context properties to a message from a WCF service using behaviors

Thursday, April 24th, 2008

The new WCF adapter in BizTalk 2006 R2 offers a lot of new possibilities. One of those is to write data to the BizTalk Message context properties directly from an exposed WCF Service. A practical use of this technic could be to write the username from the Windows credentials of the calling client into the context of the BizTalk message. This could be useful as this information is encrypted in messages that are received via the WCF adapter and isn’t possible to read when inside BizTalk. I’ll try and demonstrate the technique in this post.

If you have used the SOAP adapter before you might know that all you had to do was to turn on Windows based security for the exposed SOAP service and the username was automatically promoted to the context of the incoming BizTalk message. That username could then be used for routing, tracking which user called the service or using the value in plain text when communicating further to other connected systems. However using the WCF adapter this is not true anymore - when using the new WCF Message Security model the username and password is encrypted in the message and once the message is received by BizTalk it’s to late to read it. Basically we have to read the username in the actual service and write it into our own context property (that doesn’t get encrypted).

One way of achieving this is to read the username in the service and then to add it to the WCF Message Headers. All WCF message headers will by default be written to a the BizTalk Message context property called InboundHeaders (in the http://schemas.microsoft.com/BizTalk/2006/1/Adapters/WCF-properties namespace). First we’ll create an EndpointBehavior that will use a MessageInspector to add the username to the message header.  Finally we create BehaviorExtensionElement so we can use a WCF Custom Binding in BizTalk and configure it to add our new behavior.

Creating the new EndpointBehavior

To create the configurable behavior we’ll need the three classes we mentioned above.

  1. A class that implements the IDispatchMessageInspector interface to handle to reading and writing to the actual message.
  2. A class that implements the IEndpointBehavior interface to define what kind of endpoint we’re creating and what it should do.
  3. A class that implements the BehaviorExtensionElement abstract class to  create the behavior and make it configurable.
using System; using System.Collections.Generic; using System.Text; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Dispatcher; using System.ServiceModel.Description; using System.ServiceModel.Configuration; namespace CustomWCFProperties.Behavior { /// <summary> /// PromoteUserNameMessageInspector implements IDispatchMessageInspector and adds the name from the WindowsIdentity to a WCF header called WindowsUserName in the http://CustomWCFProperties.Schema namespace. BeforeSendReply only returns as we're not interested in handling the response. /// </summary> public class PromoteUserNameMessageInspector : IDispatchMessageInspector { #region IDispatchMessageInspector Members public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext) { string windowsUserName = ServiceSecurityContext.Current.WindowsIdentity.Name; request.Headers.Add(MessageHeader.CreateHeader("WindowsUserName", "http://CustomWCFProperties.Schema", windowsUserName)); return null; } public void BeforeSendReply(ref Message reply, object correlationState) { return; } #endregion } /// <summary> /// PromoteUserNameBehavior implements IEndpointBehavior and adds a message inspector to the dispatch behavior. Doesn't use any binding parameters, doesn't validate any configuration etc and can't be used in a client (only in a service). /// </summary> public class PromoteUserNameBehavior : IEndpointBehavior { #region IEndpointBehavior Members public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) { return; } public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime) { throw new Exception("The method or operation is not implemented."); } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher) { endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new PromoteUserNameMessageInspector()); } public void Validate(ServiceEndpoint endpoint) { return; } #endregion } /// <summary> /// Defines the behavior. /// </summary> public class PromoteUserNameBehaviorElement : BehaviorExtensionElement { protected override object CreateBehavior() { return new PromoteUserNameBehavior(); } public override Type BehaviorType { get { return typeof(PromoteUserNameBehavior); } } } }

Finally we have to sign the assembly using a strong key and add it to the GAC.

Configure the machine.config

As we need BizTalk and the WCF adapter to pick up the need behavior and make it possible to configure our receive port we need to to add the behavior element to the machine.config. The easiest way of doing this is to use the new WCF Service Configuration Editor tool and point to the machine.config file.

PromoteUserNameBehavior GAC

After the dll been added and the machine.config file has been saved the the line below should have been added to the <behaviorExtensions> element (that is if you use the same strong name key as in the sample project I’ve linked here).

<add name="addCustomWCFProperties" type="CustomWCFProperties.Behavior.PromoteUserNameBehaviorElement, AddCustomWCFPropertiesBehavior, Version=1.0.0.0, Culture=neutral, PublicKeyToken=705e34637fdffc54" />

Create the BizTalk Receive Port and Receive Location

Next thing to do is to start the BizTalk WCF Service Publishing Wizard. Choose to publish a service endpoint and make sure you enable metadata and create a receive location. In this example we’ll next choose to "Publish schemas as WCF service" and then define our service by naming service operations and so on.

When you then browse to the URL you choose to publish your service to you’ll see the nice example of how to instance the service you just defined.

WSDL code example

If we then send a request message to service (you’ll find a client as part of the attached solution here) and inspect the message and its context properties in BizTalk we’ll see that the username of the calling client is nowhere to be found.

Message No Username

Configure a WCF-Custom binding and adding a Endpoint Behavior

To add the username to the message context we’ll need to add our newly created behavior to our service. We’ll do this by switch the service over to use a WCF-Custom binding to enable configuration. We then need to add the URL in the address field, define the binding type to a wsHttpBinding and to add our addCustomeWCFProperties behavior to the list of endpoint behaviors.

Add Endpoint behavior

note  NOTE: there is a limitation in the BizTalk WCF implementation in that you can’t create the WCF-Custom receive location that uses a HTTP in-process based binding (like the wsHttpBinding used in a WCF-Custom endpoint is) first and then use the WCF Publishing Wizard to only publish a metadata endpoint.

Richard Seroter writes about it here and I found the same thing to be true.

"This error doesn’t have to do with mixing MEX endpoints and “regular” endpoints in the same IIS web site, but rather, creating MEX endpoints for in-process HTTP bindings seems to trigger this. Note that an IIS-hosted MEX endpoint CAN be created for IIS-hosted HTTP endpoints, but not for in-process hosted HTTP endpoints."

If you however choose a different binding that Http or (as in this case) publishes the metadata first and then switches over to a custom binding you’re ok.

If we then post another message to the service and inspect the message we’ll see that the behavior actually added a header and that it’s part of our BizTalk context properties. The adapter is also smart enough to know that this header isn’t part of the original headers and therefore stores in it’s own field within the context properties (you’ll find as part of the InboundHeaders block as well).

Message Username

One problem remains - the actual value of the user is nested inside a XML node and the property isn’t promoted. 

Extract and promote the value

To extract and promote the value we use an old fashion pipeline component using the following code in the execute method (the complete project is part of the downloadable sample project).

public IBaseMessage Execute(IPipelineContext pc, IBaseMessage inmsg) { StringReader reader = new StringReader(inmsg.Context.Read("WindowsUserName", "http://CustomWCFProperties.Schema").ToString()); if (reader != null) { XPathDocument document = new XPathDocument(reader); XPathNavigator navigator = document.CreateNavigator(); string value = navigator.SelectSingleNode("/").Value; inmsg.Context.Promote("WindowsUserName", "http://CustomWCFProperties.Schema", value); } return inmsg; }

All the component does is reading the XML node the value exists inside and then it reads the actual value. Finally it writes the value back and promotes it. To be able to promote the value we also have to have a Property Schema deployed with a corresponding property name and namespace (WindowsUser and http://CustomeWCFProperties.Schema in this case).

The end results looks something like this.

Message Promoted Username

The username is extracted and promoted and available for example for tracking or to for example use in a routing scenario.

This technique could of course be used for all kinds of scenarios where you like to add information to the context properties and could potentially replace a lot of the classic scenarios for custom pipelines.

All kind of comments are of course more than welcome!

Download the sample solution  here.