Using the Microsoft ESB Guidance: UDDI
Some of you may have heard by now that we are in the process of releasing the Microsoft Enterprise Service Bus (ESB) guidance. This guidance contains pre-built components, use cases, documentation and sales material that our Business Process Integration partners can use to rapidly deploy ESBs on top of BizTalk, Windows, SharePoint and SQL Servers. Over the holidays I spent some time digging into the code and thought I'd share a bit of what I've been seen.
I thought that I'd first talk about the standard ESB concept of "EndPoint Resolution" and how our guidance allows you to achieve this. Endpoint resolution is core requirement in any ESB as a Service may not always reside at the same address or endpoint. Therefore we need to be able to locate our services at runtime (wherever they may be). The Microsoft ESB guidance comes prebuilt with this capability, so I thought I post a small "How-To" blurb about how you can do it.
The Task
The basic task I thought I'd tackle is to submit a generic message from a basic client application into the ESB and have it routed it to a Service based on a entry in a local UDDI server. The following image show the Services that exist in my UDDI server.
The service that I'll wanted to submit the message to is "ENDPOINT: PostOrderMessage". You can see from the screen image that this Service has been setup with a File Folder as its endpoint. "C:\projects\Microsoft BizTalk ESB\Tests\Common\Filedrop\Output\Order %MessageID%.xml" If the solution works properly, I should be able to find my messages sitting in this folder.
ESB Concept: The "On Ramp"
As you dig into the guidance you'll quickly learn that one of the key components within it is the "On Ramp". The On Ramp acts as a central entry point into the ESB engine and it allows client applications to submit generic messages that contain processing, routing and transformation instructions. The On Ramp is a key concept to understand in order use the ESB guidance and if you're planning on using it, you'll need to have a good understanding it.
To keep things simple, the On Ramp is a Web Service that applications can use to submit XML based messages into BizTalk. On top of this, the On Ramp allow us to specify a number of processing, routing and transformation instructions that the BizTalk will follow when processing the message. To send these processing instructions, we use specific SOAP headers that are attached to our message when we submit to the On Ramp . If you've got the ESB guidance already, you can view all of the possible headers by opening the "EsbEnvGeneric.xsd" property schema file in the Microsoft.BizTalk.Esb.Schema project. This XSD file is a standard BizTalk property schema and denotes the properties that our SOAP headers will eventually be promoted into. For those of you that don't have the guidance, here a quick list of the parameters you can use when submitting your messages.
-
- ProcessingInstruction
- Itinerary
- MapRulesPolicy
- MapSelAssemblyName
- MapSelMethodCall
- MapSelTypeName
- MapType
- MapUddiLabel
- MapXPath
- EndpointAddress
- EndpointConfigurationString
- EndpointConfigurationRulesPolicy
- EndpointConfigurationUddiLabel
- EndpointConfigurationXPath
- EndpointDeliveryAgent
- EndpointMessagePattern
- EndpointRulesPolicy
- EndpointSelectAssembly
- EndpointSelectMethod
- EndpointSelectType
- EndpointUddiLabel
- EndpointXpath
For most projects, you'll ending have to work with most these headers in order to achieve full ESB capabilities, but for our simple task we'll just need to use three:
-
- EndPointUddiLabel - We use this to tell the ESB the name of the Service to lookup in the UDDI
- ProcessingInstruction - We use this to tell the ESB that the message needs to be routed.
- Itinerary - Where we'll tell the ESB that this message needs to following a routing itinerary
Building the Solution
The first thing I did was to deploy and configure the ESB guidance as per the installation instructions it ships with. I won't cover those steps here, so I'll just jump to what I did once that process was complete.
The first thing I did was to build out a client app that I could use to submit my messages to the ESB. I used a very basic Windows Forms application as my client. All I needed was a form that would let me to define my message and specify the name of the Service I wanted to route the message to.
Once I had my basic form built out, the next step I needed to take was to add a web reference to the ESB On Ramp.
Once I'd added the web reference, I had everything I needed to submit messages into the ESB. For my project, I created a function to handle all interaction with the On Ramp web service. It creates my message, assigns the three SOAP headers I need and submits the message it to the On Ramp Web Service. Here's the code:
/// <summary>
/// This function prepares a message and submits it to the ESB on ramp
/// </summary>
/// <param name="strMessageBody">The core content of the message</param>
/// <param name="strServiceName">The name of the service in the UDDI that we want to send the message to</param>
private string SubmitMessage(string strMessageBody, string strServiceName)
{
// Get an instance of the On Ramp Service
ESB.OnRamp ramp = new ESB.OnRamp();
// Assign security credentials
ramp.Credentials = new System.Net.NetworkCredential("username", "password");
// Assign values to the headers we need to perform the UDDI based routing
ramp.EsbSoapHeadersValue = new ESB.EsbSoapHeaders();
ramp.EsbSoapHeadersValue.EndpointUddiLabel = strServiceName;
ramp.EsbSoapHeadersValue.ProcessingInstruction = "ROUTE";
ramp.EsbSoapHeadersValue.Itinerary = "ROUTE";
// Get the message to send
XmlDocument doc = new XmlDocument();
doc.LoadXml(strMessageBody);
try
{
//Send the message and return the result
ramp.Receive(doc);
return "Message Submitted Successfully.";
}
catch (System.Exception ex)
{
return "Error: " + ex.Message;
}
}
As you can see, the ESB class that was created when we added our Web Reference, contains a 2 classes. The "ESB.OnRamp" class which is our proxy to the actual Web Service and the "ESB.EsbSoapHeadersValue" class. This second class contains all of the properties that relate to SOAP headers that the ESB On Ramp will use.
I setup the OnClick event of my Submit button to call this function and I passed in the values of my two textboxes. As easy as that, I had built an application that was able to send a message into my ESB architecture. Once I'd done that, the ESB engine took care of everything else. It only took me ~10 minutes to build out my app and start routing my messages to Services. Its really is pretty simple and easy to get going with this. I've included a screen cam video at the end of this entry that shows me running the solution. (Its set for 1024x768 resolution)
Now that you've seen how to route message using UDDI, some of you might wonder what exactly is going on under the BizTalk covers. So lets take a look.
The Inner Workings
The first thing to look at is obviously the On Ramp. The On Ramp is essentially a Web Service and a BizTalk receive port. The receive location within the port uses the SOAP adapter to interact with the Web Service and also uses a custom pipeline "ReceiveForESBGeneric".
The SOAP adapter is configured to use the same Web Service that we made a web reference to in our client application. The custom pipeline is responsible for promoting the SOAP headers into BizTalk message properties so that other elements within BizTalk can access our instructions. Once the receive location processes the incoming message, the message (along with its promoted properties) is published into the standard BizTalk MessageBox and the On Ramp is done its work.
At this point, another BizTalk artifact takes over, the "Generic.odx" orchestration. This orchestration comes as part of the guidance and can be found int the Microsoft.BizTalk.ESB.Agents.Delivery project. The messages received from our On Ramp receive port are sent to this orchestration using BizTalk's standard publish/subscribe mechanism. This orchestration handles all incoming messages that need to be routed.
The orchestration has a direct bound receive port based on specific filter expressions. The receive shape that has a filter setup to receive all messages that have their "ProcessingInstruction" property set to "ROUTE". Hence why I had to set that that SOAP header to use a value of "ROUTE" in my client application.
Once receiving the message, the orchestration checks to see if an proper endpoint has already been assigned to this message. If it hasn't, then the orchestration will begin the process of resolving it. This is done in the "Call Resolution Class" expression box in the "Resolve EndPoint" scope. In this expression box, a call is made to a function call "Microsoft.BizTalk.ESB.Helpers.Resolver.Resolve". This function is a part of a custom library that ships with the ESB guidance and it handles the lower level steps required to resolve the endpoint.
In our example, we specified a UDDI service name in the EndPointUddiLabelField SOAP header. Because we did this, the Resolve function will attempt to resolve the endpoint by making a call to the UDDI server. If it finds the requested service in the directory, then the endpoint is returned (as a string) to the orchestration.
This endpoint is then used to configure the "GenericDeliveryAgentSend" dynamic port . The configuration of the port is done in the "Set Endpoint" expression shape.
Once configured, the port is able to transmits our message to the Service endpoint.
As you can see, the orchestration also contains number of exception handling steps which all tie into the central exception management framework that the guidance contains. The orchestration also contains a number of "Tracing" steps which allow for easier debugging of the process.
More than just UDDI and more than just Routing
I've quickly shown how to submit a message to the ESB engine that ends up being routed based on a UDDI entry. However I must add that you aren't limited to UDDI lookups for your address resolution. Using the SOAP headers, you can tell the ESB engine to use the Business Rules Engine or you can pass in the End Point directly with your message and there are also options for using XPath. The code contained in the guidance is incredibly flexible with regards to how you want to handle your endpoint resolution.
Also, message Routing is just one feature of the guidance. It also provides some great capabilities around dynamic message transformation, centralized exception management for services, linked itineraries and more. There are more than a few projects I've worked on where I wish I had this functionality prebuilt for me!
Cheers and Keep on BizTalking...
Comments
Anonymous
January 15, 2007
good article to get started with MS ESB guidance. Overall I like MS's thinking around ESB. By this article we can understand the routing capabilities of the guidance. Also, I would like to see the dynamic message transformation. for this, I wud like to see how the guidance handles new and upgraded maps. Any samples in this regard with help.. Thanks Ashith RajAnonymous
January 19, 2007
In my last entry , I showed how developers could use our new ESB guidance to submit generic messagesAnonymous
January 24, 2007
Peter, I've gone through the esb guidance that you people have put up, not completely but enough to get an idea of how it is working and what it tries to acheive and I must say its a great effort on part of you people. But I have some questions and concerns, hope you'll answer them:
- For dynamic routing and transformation, you use generic orchestrations, wouldn't they become a point of contention when all or most of the traffic would be going through them? Yes we can load balance the on-ramp web service using NLB and Biztalk would load balance automatically for the processing of orchestration if it is on multiple host instances, but still, would that be a good idea to route most of the traffic through it?
- You say in the ESB guidance everything is loosely coupled, but we need to provide names of the services in the uddi and fully qualified names of maps from the client app, now isn't that tight coupling with the middleware?, in future if those addresses or name changes we'd need to make changes in the application also. Wouldn't that be a bad idea if we provide 'keys' rather than names or fq names, based on which esb find the required service?
- For a routing scenario, suppose if we want to implement a request-response scenario (synchronous), how do you think we should do that? because the control transfers from the generic service to the specific service and we are not in direct contact with it. Thanks for your time, Hope to listen from you soon, Regards, Sajid
Anonymous
January 25, 2007
The comment has been removedAnonymous
March 11, 2007
The comment has been removedAnonymous
May 09, 2007
Találtam egy érdekes cikket a singelton pattern kialakításáról BizTalk környezetben: http://aspallianceAnonymous
July 30, 2007
I would like to see some write ups on centralized exception management and monitoring of the ESB infrastructure. Thanks Ashith RajAnonymous
August 27, 2007
The comment has been removedAnonymous
March 10, 2008
Hi, I have ESB up and running, I tried to follow the tutorial, I have a bunch of services setup but not the one used in this nice tutorial onRampWS. I have the follwoing services: ESB.BizTalkOperationsService ESB.ExceptionHandlingServices ESB.ExceptionHandlingServices.WCF ESB.ItineraryServices ESB.ItineraryServices.Response ESB.ItineraryServices.Response.WCF ESB.ItineraryServices.WCF ESB.ResolverServices ESB.ResolverServices.WCF ESB.TransformServices ESB.TransformServices.WCFAnonymous
June 15, 2008
Hi Its a great article to start with. Can anyone explain me how should I compile my itenary file in case. In this example the endpoint info was embedded in the client app only. In case I want to supply that as the .xml file, how should I start compling my itenary info. Any help will be highly appreciated. Thanks in advance !! Sachin