Feb 192013

When you install BizTalk 2013, rx be default, cialis you can’t create itineraries. I was under the distinct impression that the ESB setup was all handled though the BizTalk setup dialog.

However, abortion I am mistaken. If you want the itinerary flow designer, there is an additional setup step required.

In the folder where the BizTalk setup is found, there is a VSIX package installer:


Once you install it, you see this confirmation dialog:

VISX Confirmation


Happy itinerary designing!

Oct 122012

I have been working on the ESB solution at the place I am at and I came across the following error as I added more and more services:

The adapter failed to transmit message going to send port “ALL.Exceptions” with URL “SQL://(local)/EsbExceptionDb/”. It will be retransmitted after the retry interval specified for this Send Port. Details:”HRESULT=”0x80040e14″ Description=”XML parsing: line 32, troche character 203, unexpected end of input”

I will spare you the detail of how I came to the solution, but it appears that complex itineraries have never been written, or the bigger the itinerary, the less likely it is to fail (? !!!).

The ultimate cause of the problem is the ItineraryHeader context property.

By default the ContextProperties table in the EsbExceptionDb is defined as 4096 bytes


And the stored procedure that load the table:


This context property is much larger than even what is documented:



Property Field

Size Limitation

255 Characters


I changed it to:




Now it works like a charm…

May 182012

So I was assisting Brian last night put the Business Rule Engine in front of the ESB solution, so it could determine which itinerary to run. I had just completed getting a flow through the ESB myself. So, after some correction of spelling mistakes (come on code, don’t be so picky about absolutely needing strings to be match exactly, do what I want, not what I say), we got down to the guts of why things aren’t working.

We implemented the BRE Policy, tested the message: right clicked the policy and chose test: viola, it worked. However, when we ran it through the Itinerary Selector pipeline component we kept getting an error stating that Itinerary_getitinerary required the parameter @name which was not provided.

The issue is that the folks at Microsoft (or subcontractors paid to do the work for them) put the following code in the Business Rule Engine resolver:

Notice that the TypedXMLDocument that will be submitted to the BRE will always be Microsoft.Practices.ESB.ResolveProviderMessage.

private static Dictionary<string, string> ResolveRules(string config, string resolver, XmlDocument message, Resolution resolution, Microsoft.Practices.ESB.Resolver.BRE.BRE bre) { Dictionary<string, string> dictionary3; int majorRevision = 0; int minorRevision = 0; Policy policy = null; Dictionary<string, string> dictionary = null; string[] strArray = null; object[] facts = null; TypedXmlDocument document = null; string documentType = "Microsoft.Practices.ESB.ResolveProviderMessage"; Dictionary<string, string> resolverDictionary = new Dictionary<string, string>(); if (!resolver.Contains(@":\")) { resolver = resolver + @":\"; } try { ... } }

So how do you create your Business Rules so it adheres to this type of TypedXmlDocument?

When you import a schema to create a vocabulary or use directly within a policy, you will need to change the following property:


To look like this:


Go ahead and use the xml document all you want!

Apr 182012

So Joe and I were talking and I was showing what I was doing, here and he said I should be blogging about this since it doesn’t appear to be documented anywhere.

The resolver I made is a separate one so it can work on getting the endpoint configuration. Here are the steps I used to configure the endpoint in the Itinerary Designer.

  • Created the service schemas using the Visual Studio WCF Wizard
  • Created the map that creates the request message
  • Opened the binding file that is created as part of the project
  • Set the Resolver to Static and set the adapter to the appropriate binding (WCF-BasicHttp in my example)

Enter the following values:


On the Endpoint Configuration:


So now you have everything set in the Endpoint configuration.

Now to move all of the settings to the BRE:


So how do you get the Endpoint Configuration into the Set End Point Configuration to section? Simply highlight the value in the Endpoint Configuration and copy (control-c) and go the BRE and paste

Publish and Deploy

Set the Resolver to BRE

Choose the Policy from the drop-down



The second tip is how to refer to XPath directly in the BRE from the BRE resolver

When you refer to a schema, remedy make sure you click on the root node and change the Document Type to Microsoft.Practices.ESB.ResolveProviderMessage and now you can drag the attributes/elements into your rules with confidence that the rule will fire. (Make sure you type the Document Type correctly Microsoft.EDB.ResolveProviderMessage will cause the rule not to fire Smile with tongue out)


Voilà deux

Apr 182012


The ESB Toolkit 2.1 could be better

  • Compared to version 2.0, it appears to be compiled for .Net 4 (that is it), however all of the projects are still set to .Net 3.5
  • It used to be the ESB Guidance 1.0 so you can ‘extend’ it. However, there is no source code to do that anymore. If I wanted to change some behavior of a pipeline, I am screwed, I can download 1.0 and take a look at how it is done (or I can reverse engineer the current pipelines), but without doing a ton of work, it is not very extendable.
  • Calling into support is nearly a waste of time, okay: more than nearly.


There are a few deficiencies I have found with ESB 2.1:

  • The itinerary designer can query various databases (management db, rules engine db) to allow drop downs in the property window to choose things that were deployed. EXCEPT: orchestrations. For this, you have to go edit a configuration file, and restart visual studio (or if you really have some stones: unload a section in SSO make additions, and then reload it, using a nearly undocumented command line)
  • The entire design of the ESB solution assumes that each service you call responds with all of the data that you need to go to the next service that will be called.
    • WHAT?! First of all, a lot of services out there only return the value it needs to return, not the original payload coupled with the new value.
    • Many, if not all services can’t be re-engineered to change the behavior, as a lot of them are managed by an outside vendor.
  • The ESB Portal has to run in compatibility mode, even in IE8.
  • If you want to re-submit messages back into the message box, all of the context properties are GONE. Essentially, resubmittal is A TOTAL WASTE.

So, I have made a few changes to accomplish what I think are a couple fundamental changes to make the ESB toolkit usable.

First: I changed the behavior of the resubmittal process: here is the code I added to the portal:

(notice the source that is provided is for which version?)

//--------------------------------------------------------------------- // File: MessageViewer.aspx.cs // // Summary: This page displays the details of a message. It renders the message body // if it is an XML or flat file. Otherwise if allows the message // body to be downloaded. // //--------------------------------------------------------------------- // This file is part of the Microsoft ESB Guidance for BizTalk // // Copyright (c) Microsoft Corporation. All rights reserved. // // This source code is intended only as a supplement to Microsoft BizTalk // Server 2006 R2 release and/or on-line documentation. See these other // materials for detailed information regarding Microsoft code samples. // // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY // KIND, WHETHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR // PURPOSE. //---------------------------------------------------------------------- using System; using System.Data; using System.Configuration; using System.Collections; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using System.ComponentModel; using System.Net; using System.IO; using System.Text; using System.Xml; using System.ServiceModel; using ESB.BAM.Service.Implementation; using ESB.Exceptions.Service.Implementation; using System.Collections.Generic; namespace Microsoft.Practices.ESB.Portal { public partial class MessageViewer : System.Web.UI.UserControl { #region Properties /// <summary> /// True if the message is text based, false otherwise. /// </summary> private bool MessageIsText { get { return (((Label)this.MessageView.FindControl("contentTypeLabel")).Text.Contains("text") || ((Label)this.MessageView.FindControl("contentTypeLabel")).Text.Equals("application/octet-stream")); } } /// <summary> /// Indicates whether a resubmission attempt has been made on the message. /// </summary> private bool _resubmitAttempted; private bool ResubmitAttempted { get { return _resubmitAttempted; } set { _resubmitAttempted = value; } } /// <summary> /// Indicates whether the message has been successfully resubmitted. /// </summary> private bool _resubmitSuccessful; private bool ResubmitSuccessful { get { return _resubmitSuccessful; } set { _resubmitSuccessful = value; } } /// <summary> /// Indicated whether the control is allowed to go into edit mode. /// </summary> private bool _editModeAvailable; private bool EditModeAvailable { get { return _editModeAvailable; } set { _editModeAvailable = value; } } /// <summary> /// Get the selected receive location from the 'receiveLocationList' DropDownlist. /// </summary> private string SelectedReceiveLocation { get { if (((DropDownList)this.MessageView.FindControl("receiveLocationList")).SelectedItem.Text == "Submit to Routing URL") { return "RoutingURL"; } else { return ((DropDownList)this.MessageView.FindControl("receiveLocationList")).SelectedValue; } } } /// <summary> /// Gets the message content type (MIME type). /// </summary> private string MessageContentType { get { return ((Label)this.MessageView.FindControl("contentTypeLabel")).Text; } } /// <summary> /// This property indicates whether or not the page is in the mode to /// edit and resubmit the message. This is determined by the esb:Mode /// querystring parameter containing the value: "Edit". /// </summary> private bool _editMode; protected bool EditMode { set { _editMode = value; } get { return _editMode; } } #endregion protected void Page_PreRender(object sender, EventArgs e) { SetControlVisibility(); SetControlEditability(); RenderMessageBody(); if (!IsPostBack) { PopulateReceiveLocationList(); } } private void BindGrid() { IExceptionService client = null; try { client = PortalHelper.GetExceptionService(); List<usp_select_ContextPropertiesResult> contextProperties = client.GetContextProperties(new Guid(Request.QueryString["esb:MessageID" ])); contextPropertiesView.DataSource = contextProperties; contextPropertiesView.DataBind(); } context; } protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { IExceptionService client = null; try { client = PortalHelper.GetExceptionService(); List<usp_select_MessagesResult> messages = client.GetMessages(Request.QueryString["esb:FaultID"], Request.QueryString["esb:MessageID"]); MessageView.DataSource = messages; MessageView.DataBind(); BindGrid(); } catch (Exception ex) { throw ex; } finally { if (client != null) { ((IDisposable)client).Dispose( ); } } } this.EditMode = (Request.QueryString["esb:Mode"] == "Edit"); this.EditModeAvailable = (((HtmlInputHidden)this.MessageView.FindControl("resubmitSuccessful")).Value == "True" || !this.MessageIsText || this.EditMode) ? false : true; this.ResubmitAttempted = (((HtmlInputHidden)this.MessageView.FindControl("resubmitAttempted")).Value == "True"); this.ResubmitSuccessful = (((HtmlInputHidden)this.MessageView.FindControl("resubmitSuccessful")).Value == "True"); if (this.ResubmitSuccessful) { ((Label)this.MessageView.FindControl("resubmissionLabel")).Text = "<img src='../images/severityinformation.gif' style='vertical-align:middle;'/>&nbsp;This message has been successfully resubmitted."; ((Label)this.MessageView.FindControl("resubmissionLabel")).ForeColor = System.Drawing.Color.Black; } else if (this.ResubmitAttempted) { ((Label)this.MessageView.FindControl("resubmissionLabel")).Text = "<img src='../images/severitycritical.gif' style='vertical-align:middle;'/>&nbsp;A message resubmission was attempted but failed."; ((Label)this.MessageView.FindControl("resubmissionLabel")).ForeColor = System.Drawing.Color.Red; } } /// <summary> /// Calls the resubmit helper class to transmit the message back to BizTalk. Logs the result to the portal audit log. /// </summary> protected void resubmitButton_Click(object sender, EventArgs e) { //Resubmit the message to the selected receive location via HTTP string messageID = ((Label)this.MessageView.FindControl("messageIDLabel")).Text; string statusCode; string statusMessage; bool result = ResubmitMessage(((DropDownList)this.MessageView.FindControl("receiveLocationList")).SelectedValue, out statusCode, out statusMessage); this.ResubmitAttempted = true; if (result == false) { ((Label)this.MessageView.FindControl("resubmissionLabel")).Text = "<img src='../images/severitycritical.gif' style='vertical-align:middle;'/>&nbsp;The resubmission failed: " + statusCode + " - " + statusMessage; ((Label)this.MessageView.FindControl("resubmissionLabel")).ForeColor = System.Drawing.Color.Red; ((Label)this.MessageView.FindControl("resubmissionLabel")).Visible = true; } else { this.ResubmitSuccessful = true; this.EditMode = false; this.EditModeAvailable = false; ((Label)this.MessageView.FindControl("resubmissionLabel")).Text = "<img src='../images/severityinformation.gif' style='vertical-align:middle;'/>&nbsp;This message has been successfully resubmitted."; ((Label)this.MessageView.FindControl("resubmissionLabel")).ForeColor = System.Drawing.Color.Black; ((Label)this.MessageView.FindControl("resubmissionLabel")).Visible = true; } //Update the resubmission status in the Message table UpdateMessageResubmissionStatus(result); //Write an audit log event for the message resubmission AuditMessageResubmission(result, statusCode, statusMessage, ((DropDownList)this.MessageView.FindControl("receiveLocationList")).SelectedValue); } /// <summary> /// Resubmits the message body to the URL selected in the resubmit location DropDownList. /// </summary> /// <returns>True if the message was successfully resubmitted, false otherwise.</returns> private bool ResubmitMessage(string resubmitUrl, out string responseCode, out string responseMessage) { bool result = false; // returned. if (resubmitUrl.ToUpper().Equals("WCF ONRAMP")) { // resubmit message and capture the result System.Xml.XmlDocument doc = new System.Xml.XmlDocument(); doc.LoadXml(((TextBox)this.MessageView.FindControl("messageBodyBox")).Text); result = MessageResubmitter.ResubmitWCF(doc); if (result == true) { responseCode = "202"; responseMessage = "Successfully sumbitted to WCF OnRamp"; } else { responseCode = "500"; responseMessage = "Failure submitting to WCF OnRamp"; } } else if (resubmitUrl.ToUpper().Equals("SOAP ONRAMP")) { // resubmit message and capture the result System.Xml.XmlDocument doc = new System.Xml.XmlDocument(); doc.LoadXml(((TextBox)this.MessageView.FindControl("messageBodyBox")).Text); result = MessageResubmitter.ResubmitSOAP(doc); if (result == true) { responseCode = "202"; responseMessage = "Successfully sumbitted to SOAP OnRamp"; } else { responseCode = "500"; responseMessage = "Failure submitting to SOAP OnRamp"; } } else { HttpStatusCode statusCode; string MessageToSubmit = getCompleteContent(((TextBox)this.MessageView.FindControl("messageBodyBox" )).Text); //check to see if we need to set a proxy using (Stream messageReader = this.GetMessageDataStream(MessageToSubmit)) { HttpWebRequest HttpWRequest = (HttpWebRequest)WebRequest.Create(resubmitUrl); // TODO: (jsk) put settings in web.config // set the name of the user agent. This is the client name that is passed to IIS HttpWRequest.Headers.Set("Pragma", "no-cache"); HttpWRequest.UserAgent = Page.User.Identity.Name; HttpWRequest.KeepAlive = true; //this is the default HttpWRequest.Timeout = 300000; HttpWRequest.Method = "POST"; HttpWRequest.ContentType = MessageContentType; HttpWRequest.Credentials = CredentialCache.DefaultCredentials; // resubmit message and capture the result statusCode = MessageResubmitter.ResubmitHTTP(HttpWRequest, messageReader); //Anything between 200 and 299 is considered success result = ((int)statusCode > 199 && (int)statusCode < 301); responseCode = ((int)statusCode).ToString(); responseMessage = Enum.GetName(typeof(HttpStatusCode), statusCode); } } return result; } private string getCompleteContent(string body) { string UberDocument = "<ns1:Message xmlns:ns1=\"http://Message\">"; UberDocument += SerializeContext(); UberDocument += "<ns1:Body>" + body + "</ns1:Body></ns1:Message>"; return UberDocument; } /// <summary> /// Extracts and returns a Stream from the given string. /// </summary> /// <param name="messageDataString">The string to extract into a stream.</param> /// <returns>A stream from the given string.</returns> private Stream GetMessageDataStream(string messageDataString) { MemoryStream ms = new MemoryStream(ASCIIEncoding.Default.GetBytes(messageDataString)); return ms; } /// <summary> /// Updates the ResubmitAttempted and ResubmitSuccessful fields on the Message table /// in the database. /// </summary> /// <param name="success">True if the message was successfully resubmitted, false otherwise.</param> private void UpdateMessageResubmissionStatus(bool success) { IExceptionService client = null; try { client = PortalHelper.GetExceptionService(); client.InsertMessage(((Label)this.MessageView.FindControl("messageIDLabel")).Text, true, success); } catch (Exception ex) { throw ex; } finally { if (client != null) { ((IDisposable)client).Dispose( ); } } //DataSets.Faults.MessagesDataTable messageTable = new DataSets.Faults.MessagesDataTable(); ////The only values that are used by this call are MessageID, ResubmissionAttempted, and ResubmissionSuccessful. ////The 2nd new Guid is just there because null is not accepted. //messageTable.AddMessagesRow(((Label)this.MessageView.FindControl("messageIDLabel")).Text, null, null, null, null, null, null, null, true, success, DateTime.Now); //MessagesTableAdapter messageAdapter = new MessagesTableAdapter(); //messageAdapter.Update(messageTable); } /// <summary> /// Writes the failed or successful resubmission event to the audit log. /// </summary> /// <param name="success">True if the message was successfully resubmitted, false otherwise.</param> private void AuditMessageResubmission(bool success, string resubmitCode, string resubmitMessage, string resubmitUrl) { IExceptionService client = null; try { client = PortalHelper.GetExceptionService(); AuditLog auditLog = new AuditLog(); auditLog.ActionName = success ? "SuccessfulResubmit" : "UnsuccessfulResubmit"; auditLog.AuditDate = DateTime.UtcNow; auditLog.AuditUserName = Page.User.Identity.Name; auditLog.MessageID = new Guid(((Label)this.MessageView.FindControl("messageIDLabel")).Text); auditLog.ResubmitURL = resubmitUrl; auditLog.ResubmitCode = resubmitCode; auditLog.ResubmitMessage = resubmitMessage; auditLog.MessageData = ((TextBox)this.MessageView.FindControl("messageBodyBox")).Text; //client.InsertAuditLog(auditLog); } catch (Exception ex) { throw ex; } finally { if (client != null) { ((IDisposable)client).Dispose( ); } } ////Insert audit information //AuditLogTableAdapter auditLogTA = new AuditLogTableAdapter(); //DataSets.AuditLog.AuditLogDataTable auditLogTable = new DataSets.AuditLog.AuditLogDataTable(); //DataSets.AuditLog.AuditLogRow auditRow = auditLogTable.NewAuditLogRow(); //auditRow.ActionName = success ? "SuccessfulResubmit" : "UnsuccessfulResubmit"; //auditRow.AuditDate = DateTime.UtcNow; //auditRow.AuditUserName = Page.User.Identity.Name; //auditRow.MessageID = new Guid(((Label)this.MessageView.FindControl("messageIDLabel")).Text); //auditRow.ResubmitURL = resubmitUrl; //auditRow.ResubmitCode = resubmitCode; //auditRow.ResubmitMessage = resubmitMessage; ////auditRow.ContentType = (((Label)this.MessageView.FindControl("contentTypeLabel")).Text); //if (success) //{ // auditRow.MessageData = ((TextBox)this.MessageView.FindControl("messageBodyBox")).Text; //} //auditLogTable.AddAuditLogRow(auditRow); //auditLogTA.Update(auditLogTable); } /// <summary> /// Populates the receive location selection list with the WCF OnRamp, the SOAP OnRamp, and/or all HTTP receive locations on the BizTalk group. Flat File resubmission is limited to HTTP receive /// locations only, while XML document resubmission can be to WCF, SOAP, or HTTP. /// </summary> private void PopulateReceiveLocationList() { BizTalkOperationsService.Operations queryService = Microsoft.Practices.ESB.Portal.BizTalkOperationsService.Operations.CreateInstance(); BizTalkOperationsService.BTSysStatus sysStatus = queryService.ReceiveLocations(string.Empty); //Loop through the receive locations and extract the HTTP and WCF HTTP receive locations. int i = 0; ArrayList httpRcvLocs = new ArrayList(); foreach (BizTalkOperationsService.BTReceiveLocation rcvLoc in sysStatus.ReceiveLocations) { if (rcvLoc.Handler.ProtocolName.ToUpper().Equals("HTTP")) { rcvLoc.Address = "http://" + rcvLoc.Handler.Host.HostInstances[0].ServerName + rcvLoc.Address; httpRcvLocs.Add(rcvLoc); i++; } } DropDownList receiveLocList = ((DropDownList)this.MessageView.FindControl("receiveLocationList")); //Add a default selection to the applications list if (String.IsNullOrEmpty(((Label)this.MessageView.FindControl("routingURLLabel")).Text)) { receiveLocList.Items.Add(new ListItem("Select a receive location.", null)); } else { receiveLocList.Items.Add(new ListItem("Submit to Routing URL", ((Label)this.MessageView.FindControl("routingURLLabel")).Text)); } //Add the WCF and SOAP OnRamps if the message is not a flat file if (((Label)this.MessageView.FindControl("contentTypeLabel")).Text.ToUpper() != "TEXT/PLAIN") { receiveLocList.Items.Add(new ListItem("WCF OnRamp", "WCF OnRamp")); //URL will be retrieved from web.config receiveLocList.Items.Add(new ListItem("SOAP OnRamp", "SOAP OnRamp")); //URL will be retrieved from web.config } //Populate the receive locations list with the receive locations from BizTalk receiveLocList.AppendDataBoundItems = true; receiveLocList.DataSource = httpRcvLocs; receiveLocList.DataTextField = "Name"; receiveLocList.DataValueField = "Address"; receiveLocList.DataBind(); } /// <summary> /// This method shows or hides the correct control to display the message body. When the message /// body is text based, it is rendered to the screen in a TextBox. When the message body is binary /// a link is displayed to download it. /// </summary> private void RenderMessageBody() { //If the message content type is text if (this.MessageIsText) { //Make the message body download link invisible. ((TextBox)this.MessageView.FindControl("messageBodyBox")).Visible = true; } } /// <summary> /// Reads the mode from the querystring, and shows/hides the appropriate buttons. /// By default the Edit button is shown, if the mode = Edit, the Resubmit and Cancel buttons /// are shown. /// </summary> private void SetControlVisibility() { ((HtmlGenericControl)this.MessageView.FindControl("editButton")).Visible = this.EditModeAvailable; ((HtmlAnchor)this.MessageView.FindControl("messageBodyAnchor")).Visible = this.EditModeAvailable; ((LinkButton)this.MessageView.FindControl("resubmitButton")).Visible = this.EditMode; ((HtmlGenericControl)this.MessageView.FindControl("cancelButton")).Visible = this.EditMode; ((DropDownList)this.MessageView.FindControl("receiveLocationList")).Visible = this.EditMode; ((Label)this.MessageView.FindControl("resubmissionLabel")).Visible = this.ResubmitAttempted; } /// <summary> /// Sets the editability of controls based on whether the page is in edit mode. /// </summary> private void SetControlEditability() { TextBox messageBodyBox = this.MessageView.FindControl("messageBodyBox") as TextBox; messageBodyBox.ReadOnly = !this.EditMode; if (!this.EditMode) { messageBodyBox.BackColor = System.Drawing.Color.WhiteSmoke; } else { messageBodyBox.BackColor = System.Drawing.Color.White; } } public string GetCrumbedString(object t, int crumbAt) { string text = t.ToString(); if (text.Length > crumbAt) { //return "<span title='" + text + "'>" + HttpUtility.HtmlEncode( PortalHelper.CrumbString(text, crumbAt)) + "</span>"; return HttpUtility.HtmlEncode(PortalHelper.CrumbString(text, crumbAt)); } else { return text; } } protected void labelHeaderCaption_PreRender(object sender, EventArgs e) { Label me = (Label)sender; if (Request.QueryString["esb:Mode"] == "Edit") { me.CssClass = "iconMessageEdit"; } else { me.CssClass = "iconMessage"; } } protected void contextPropertiesView_RowDataBound(object sender, GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.DataRow) { Label name = e.Row.FindControl("lblName") as Label; if (name != null && name.Text.Equals("ItineraryHeader", StringComparison.InvariantCultureIgnoreCase)) { Label content = e.Row.FindControl("lblValueOriginal") as Label; if (content != null && !string.IsNullOrEmpty(content.Text)) { string contentData = HttpUtility.HtmlDecode(content.Text); XmlDocument xml = new XmlDocument(); xml.LoadXml(contentData); XmlNodeList nodeList = xml.GetElementsByTagName("Itinerary"); if (nodeList.Count > 0) { XmlNode node = nodeList[0]; if (node.Attributes["uuid"] != null) { string itineraryUuid = node.Attributes["uuid"].Value; HyperLink lnk = e.Row.FindControl("hlnkItineraries") as HyperLink; if (lnk != null) { lnk.Visible = true; lnk.NavigateUrl = "Itineraries.aspx?uuid=" + itineraryUuid; } } } } } } } protected void contextPropertiesView_PageIndexChanging(object sender, GridViewPageEventArgs e) { contextPropertiesView.PageIndex = e.NewPageIndex; BindGrid(); } } }

This creates a message that looks like this:

<ns1:Message xmlns:ns1="http://Message"> <ns1:Context> <ns1:Property Name="" Type="" Value="" /> <!--All of the context properties associated--> <!--Except those from the All.Exceptions--> <!--And the InboundTransportLocation (cause it is always the ESB Exception)--> <!--Along with any that has the error-report--> </ns1:Context> <ns1:Body> Content that is displayed in the text box </ns1:Body> </ns1:Message>

Well, the problem is that we don’t have a schema that looks like this message. I really just want to submit the content contained in the Body. So I created a decode pipeline component that access the SSO Configuration Store to promote certain properties of the message as it comes back into BizTalk.

using System; using System.IO; using System.Xml; using System.Xml.XPath; using System.ComponentModel; using System.Collections; using Microsoft.BizTalk.Message.Interop; using Microsoft.BizTalk.Component.Interop; using Microsoft.Win32; using System.Web; using System.Text; using SSO.Utility; using System.Diagnostics; namespace StottCreations.ContextReader { public class PromoteContext { /// <summary> /// Implements a pipeline component that takes unwraps the data from the body of the xml document /// and promotes the values in the content of the message to the context of the messaage payload. /// </summary> /// <remarks> /// </remarks> [ComponentCategory(CategoryTypes.CATID_PipelineComponent)] [ComponentCategory(CategoryTypes.CATID_Decoder)] [System.Runtime.InteropServices.Guid("FA7F9C55-6E8E-4855-8DAC-FA1BC8A499E2")] public class PromoteContextComponent : Microsoft.BizTalk.Component.Interop.IBaseComponent, Microsoft.BizTalk.Component.Interop.IComponent, Microsoft.BizTalk.Component.Interop.IPersistPropertyBag, Microsoft.BizTalk.Component.Interop.IComponentUI { #region Pipeline Properties private string ssoApplication = null; /// <summary> /// Application that contains all of the properties to be passed through the pipeline /// </summary> public string SSOApplication { get { return ssoApplication; } set { ssoApplication = value; } } #endregion #region IBaseComponent /// <summary> /// Name of the component. /// </summary> [Browsable(false)] public string Name { get { return "Context Promoter"; } } /// <summary> /// Version of the component. /// </summary> [Browsable(false)] public string Version { get { return "1.0"; } } /// <summary> /// Description of the component. /// </summary> [Browsable(false)] public string Description { get { return "Promotes context data from message and passes the data to Dissassembler"; } } #endregion #region IComponent public IBaseMessage Execute(IPipelineContext pc, IBaseMessage inmsg) { try { inmsg = Promote(inmsg); inmsg.BodyPart.Data = TransformMessage(inmsg.BodyPart.GetOriginalDataStream()); } catch (Exception ex) { EventLog.WriteEntry("Promote Pipeline Component", ex.Message, EventLogEntryType.Error); } return inmsg; } #endregion #region Helper function /// <summary> /// Extracts data from message /// </summary> /// <param name="stm">Stream with input XML message</param> /// <returns>Message</returns> public Stream TransformMessage(Stream stm) { Stream s = null; try { //Load Xml stream in XmlDocument. XmlDocument doc = new XmlDocument(); doc.Load(stm); XPathNavigator nav = doc.CreateNavigator(); XPathNodeIterator iter; // retrieve a node-set via XPath iter = nav.Select("/*[local-name()='Message' and namespace-uri()='http://Message']/*[local-name()='Body' and namespace-uri()='http://Message']"); // make sure a match was found while (iter.MoveNext()) { string data = iter.Current.InnerXml; s = new MemoryStream(ASCIIEncoding.Default.GetBytes(data)); } } catch (Exception e) { System.Diagnostics.Trace.WriteLine(e.Message); System.Diagnostics.Trace.WriteLine(e.StackTrace); throw e; } return s; } private IBaseMessage Promote(IBaseMessage inmsg) { string ErrorMsg = string.Empty; XmlDocument doc = new XmlDocument(); doc.Load(inmsg.BodyPart.GetOriginalDataStream()); XPathNavigator nav = doc.CreateNavigator(); XPathNodeIterator iter; // retrieve a node-set via XPath iter = nav.Select("/*[local-name()='Message' and namespace-uri()='http://Message']/*[local-name()='Context' and namespace-uri()='http://Message']/*[local-name()='Property' and namespace-uri()='http://Message']"); // make sure a match was found while (iter.MoveNext()) { //Check the SSO Application to see if we should be promoting it, otherwise skip it if (System.Convert.ToBoolean(SSOClientHelper.Read(SSOApplication, HttpUtility.HtmlDecode(iter.Current.GetAttribute("Name", ""))))) { try { string Name = HttpUtility.HtmlDecode(iter.Current.GetAttribute("Name", "")); string Type = HttpUtility.HtmlDecode(iter.Current.GetAttribute("Type", "")); string Value = HttpUtility.HtmlDecode(iter.Current.GetAttribute("Value", "")); inmsg.Context.Promote(Name, Type, Value); } catch (Exception) { //We could not promote this particular property, let's report it and go on ErrorMsg += "The " + SSOApplication + " SSO Application was attempting to promote " + HttpUtility.HtmlDecode(iter.Current.GetAttribute("Name", "")) + ", but it it can't be promoted, please remove it./r/n"; } } } if (ErrorMsg.Length > 0) EventLog.WriteEntry("Promote Pipeline Component", ErrorMsg.Substring(0,2048), EventLogEntryType.Warning); return inmsg; } #endregion #region IPersistPropertyBag /// <summary> /// Gets class ID of component for usage from unmanaged code. /// </summary> /// <param name="classid">Class ID of the component.</param> public void GetClassID(out Guid classid) { classid = new System.Guid("DA7F9C55-6E8E-4855-8DAC-FA1BC8A499E2"); } /// <summary> /// Not implemented. /// </summary> public void InitNew() { } public void Load(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, Int32 errlog) { string val = (string)ReadPropertyBag(pb, "SSOApplication"); if (val != null) ssoApplication = val; } /// <summary> /// Saves the current component configuration into the property bag. /// </summary> /// <param name="pb">Configuration property bag.</param> /// <param name="fClearDirty">Not used.</param> /// <param name="fSaveAllProperties">Not used.</param> public void Save(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, Boolean fClearDirty, Boolean fSaveAllProperties) { object val = (object)ssoApplication; WritePropertyBag(pb, "SSOApplication", val); } /// <summary> /// Reads property value from property bag. /// </summary> /// <param name="pb">Property bag.</param> /// <param name="propName">Name of property.</param> /// <returns>Value of the property.</returns> private static object ReadPropertyBag(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName) { object val = null; try { pb.Read(propName, out val, 0); } catch (System.ArgumentException) { return val; } catch (Exception ex) { throw new ApplicationException(ex.Message); } return val; } private static void WritePropertyBag(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName, object val) { try { pb.Write(propName, ref val); } catch (Exception ex) { throw new ApplicationException(ex.Message); } } #endregion #region IComponentUI /// <summary> /// Component icon to use in BizTalk Editor. /// </summary> [Browsable(false)] public IntPtr Icon { get { return IntPtr.Zero; } } /// <summary> /// The Validate method is called by the BizTalk Editor during the build /// of a BizTalk project. /// </summary> /// <param name="obj">Project system.</param> /// <returns> /// A list of error and/or warning messages encounter during validation /// of this component. /// </returns> public IEnumerator Validate(object projectSystem) { if (projectSystem == null) throw new System.ArgumentNullException("No project system"); IEnumerator enumerator = null; ArrayList strList = new ArrayList(); try { } catch (Exception e) { strList.Add(e.Message); enumerator = strList.GetEnumerator(); } return enumerator; } #endregion } } }

So in the pipeline that I have used to submit xml data back to the message box looks like this:


Within the SSO Configuration, I can promote as many (or few) properties as I need. Here is the only things I wanted to promote:


This means that it will take all of the properties, and only promote ReceivedFileName and OrderedDelivery.

There are certain properties that are not promotable, and as such, it will not blow up, but simply write an entry into the event log and continue on. You should really remove it from the SSO Configuration Store.

To address the need to carry data between one service call to the next, I had to modify the MessageEnrichment orchestration.

I modified it in these steps:

  1. I went through and created proper labels (NotOneSingleWordThatMakesItReallyHardToRead)
  2. Then I went through and created message names that made sense to an ordinary human
  3. I added a separate resolver in the middle so that there was a completely different step to determine the destination, instead of setting the map AND the destination in the resolver
  4. I took the copy context from the original message to the response of the service call. (Why in the world would you do that anyway? The response has a different target name space than the original message.)

This is what the new orchestration looks like:


Which means that I have Itineraries that look like this:


So if I need to call another service, I simply need to add the same Orchestration Extender, define the next three resolvers:

  1. Map that creates the request to the service
  2. Defines the endpoint configuration for the service
  3. The map the enhances the canonical message

I really means that it REALLY isn’t ESB though, it is a series of orchestrations chained together that call services.

Not cool…


Dec 042010

Is anyone else wondering?

  1. If the ESB Toolkit 2.1 is designed for BizTalk 2010, vcialis 40mg why are all of the sample projects still compiled in Visual Studio 2008?
  2. Why the projects are still referring to the old .Net version (which is incorrect in this project)?
    which by changing the .Net version changes the references:

Does anyone have an idea?

(Could it be that you can use the ESB Toolkit 2.1 with BizTalk 2009?)

Dec 042010

While working on this sample, I came across the following errors:

  1. I needed to change the version of .NET from 3.5 to 4.0 in the properties of the project.
  2. I got the following error when I compiled the error: The type ‘Microsoft.VisualStudio.Modeling.ModelElement’ is defined in an assembly that is not referenced. You must add a reference to assembly ‘Microsoft.VisualStudio.Modeling.Sdk.10.0, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’.    C:\Projects\Microsoft.Practices.ESB\Source\Samples\Designer Extensibility Samples\Extenders.Itinerary.OrchestrationSample\Extenders.Itinerary.OrchestrationSample\OrchestrationSampleExtender.cs
  3. This made me install the following components:
  4. Visual Studio 2010 SDK
    Visual Studio 2010 Visualization and Modeling SDK
  5. This then required me to reference the following assembly in the project: C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.VisualStudio.Modeling.Sdk.10.0\v4.0_10.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.Modeling.Sdk.10.0.dll
  6. Once I built the two projects, in the directions (step 7) it states: In Windows Explorer, open the \Lib folder under the Itinerary Designer install path. This actual path is: C:\Program Files (x86)\Microsoft BizTalk ESB Toolkit 2.1\Tools\Itinerary Designer\Lib\
Nov 172010

After much digging while trying to have a 100% silent install of BizTalk, I have determined that a silent install of the ESB 2.1 Toolkit is not possible.

I have made it as hands free as I think is possible. The below scripts are designed for a single server installation.

Here is the batch script that needs to be run:

  1: start /w pkgmgr /iu:IIS-ASPNET;IIS-BasicAuthentication;IIS-WindowsAuthentication;IIS-IIS6ManagementCompatibility;IIS-Metabase
  2: msiexec.exe /qn /i "\\BizTalk Server 2010 Enterprise\BizTalk ESB Toolkit 2.1-x64.msi"
  3: "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\VSIXInstaller.exe" "C:\Program Files (x86)\Microsoft BizTalk ESB Toolkit 2.1\Tools\Itinerary Designer\Microsoft.Practices.Services.Itinerary.DslPackage.vsix" /q /s:Ultimate /v:10.0
  4: move "C:\Program Files (x86)\Microsoft BizTalk ESB Toolkit 2.1\Bin\ESBConfigurationTool.exe.config" "C:\Program Files (x86)\Microsoft BizTalk ESB Toolkit 2.1\Bin\ESBConfigurationTool.exe.config.old"
  5: copy "\\BizTalk Server 2010 Enterprise\BizTalk Server\ESBConfigurationTool.exe.config" "C:\Program Files (x86)\Microsoft BizTalk ESB Toolkit 2.1\Bin\ESBConfigurationTool.exe.config"
  6: echo "Run ESBConfigurationTool.exe and press <Enter> when complete"
  7: pause
  8: "C:\Program Files (x86)\Microsoft BizTalk Server 2010\BTSTask.exe" ImportApp -Package:"C:\Program Files (x86)\Microsoft BizTalk ESB Toolkit 2.1\Microsoft.Practices.ESB.CORE_NOBINDING64.msi" -ApplicationName:Microsoft.Practices.ESB -Overwrite
  9: "C:\Program Files (x86)\Microsoft BizTalk Server 2010\BTSTask.exe" ImportBindings /Source:"\\BizTalk Server 2010 Enterprise\BizTalk Server\Microsoft.Practices.ESB.CORE_Bindings.xml" -Application:Microsoft.Practices.ESB
 10: "C:\Program Files (x86)\Microsoft BizTalk Server 2010\BTSTask.exe" ImportApp -Package:"C:\Program Files (x86)\Microsoft BizTalk ESB Toolkit 2.1\Microsoft.Practices.ESB.ExceptionHandling_NOBINDING64.msi" -ApplicationName:Microsoft.Practices.ESB -Overwrite
 11: "C:\Program Files (x86)\Microsoft BizTalk Server 2010\BTSTask.exe" ImportBindings /Source:"\\BizTalk Server 2010 Enterprise\BizTalk Server\Microsoft.Practices.ESB.ExceptionHandling_Bindings.xml" -Application:Microsoft.Practices.ESB
 12: msiexec.exe /qn /i "C:\Program Files (x86)\Microsoft BizTalk ESB Toolkit 2.1\Microsoft.Practices.ESB.CORE_NOBINDING64.msi"
 13: msiexec.exe /qn /i "C:\Program Files (x86)\Microsoft BizTalk ESB Toolkit 2.1\Microsoft.Practices.ESB.ExceptionHandling64.msi"
 14: iisreset
 15: pause

Line 1 adds the necessary additions to IIS

Line 2 actually installs the ESB components, which in turn adds the items to the start menu and unpacks the BizTalk msi’s etc.

Line 3 installs the Itinerary Designer into Visual Studio

Line 4 archives the default configuration file for the ESBConfigurationTool.exe application

Line 5 copies a new configuration file for the ESBConfigurationTool.exe to use

Line 6 echoes that it is time to run the configuration tool

Line 7 waits until the configuration has been run

Line 8 imports the ESB Core application into the BizTalk Administration Console

Line 9 applies the bindings (this needs to be customized from the samples provided during the install (Line 2))

Line 10 import  the ESB Exception application into the BizTalk Administration Console

Line 11 applies the bindings like Line 9

Line 12 installs the ESB Core application into the GAC

Line 13 installs the ESB Exception application into the GAC

Line 14 resets IIS since modifications were made in step 1

Here is a sample of the configuration file, so when you open up the ESBConfiguration tool, you simply need to enable each of the features, press the Apply Configuration tool and walk through it.

<?xml version="1.0" encoding="utf-8" ?>
    <!-- Management Database -->
    <add key="ServerInstance" value="."/>
    <add key="DatabaseName" value="ESBManagementDB"/>
    <add key="Username" value="CORP\svcBTSHost"/>
    <add key="Password" value="P4ssw0rd!"/>
    <add key="BizTalkAppGroup" value="CORP\AppUsers"/>
    <add key="BizTalkAdminGroup" value="CORP\ServerAdmin"/>
    <add key="UseSqlAuthentication" value="False"/>
    <!-- Itinerary Database -->
    <add key="ItineraryServerInstance" value="."/>
    <add key="ItineraryDatabaseName" value="ExceptionDB"/>
    <add key="ItineraryUsername" value="CORP\svcBTSHost"/>
    <add key="ItineraryPassword" value="P4ssw0rd!"/>
    <add key="ItineraryBizTalkAppGroup" value="CORP\AppUsers"/>
    <add key="ItineraryBizTalkAdminGroup" value="CORP\ServerAdmin"/>
    <add key="BizTalkIsolatedHostGroup" value="CORP\IsolatedUsers"/>
    <add key="ItineraryUseSqlAuthentication" value="False"/>
    <!-- Core Services-->
    <add key="CoreWebSiteName" value="."/>
    <add key="CoreUserAccount" value="CORP\svcBTSIsoHost"/>
    <add key="CoreUserAccountPassword" value="P4ssw0rd!"/>
    <add key="CoreBizTalkIsolatedHostGroup" value="CORP\IsolatedUsers"/>
    <!-- Exception Services-->
    <add key="ExceptionWebSiteName" value="."/>
    <add key="ExceptionUserAccount" value="CORP\svcBTSIsoHost"/>
    <add key="ExceptionUserAccountPassword" value="P4ssw0rd!"/>
    <add key="ExceptionBizTalkIsolatedHostGroup" value="CORP\IsolatedUsers"/>
    <!-- Configuration-->
    <add key="ConfigurationSource" value="False" />
    <add key="ApplicationName" value="ESB Toolkit" />
    <add key="ContactInformation" value="sucker@company.com" />
    <add key="AdminGroupName" value="CORP\SSOAdmin" />
    <add key="UserGroupName" value="CORP\AppUsers" />
    <add key="ConfigurationFilePath" value="C:\Program Files (x86)\Microsoft BizTalk ESB Toolkit 2.1\esb.config" />
      <add name="ESBConfigTool" value="4" />
    <trace autoflush="true" indentsize="4">
        <add name="FileListener"