Wednesday, January 31, 2007

JkDefrag v3.6

JkDefrag v3.6

Here's a handy little defrag utility.

Tuesday, January 23, 2007

BizTalk - Make the Port Operation Unique

Kevin Lam's WebLog : An orchestration pattern that can hog the master message box CPU

This is a compelling article on why the operation property of an orchestration port should be uniquely named.

Monday, January 22, 2007

How to Debug a BizTalk Rules Policy in Code

Rule engine - Another way to debug the rule engine

I was experiencing an unreported error when I was trying to dynamically call a BizTalk 2006 rules policy in C# code. The policy ran and gave me no exception information and was annoying me to no end!

It turns out the issue had to do with facts and namespaces. I didn't discover this, however, until I learned from the link above how to put a debug trace into the policy so it would tell me what was going on.

Here's a snippet:

TypedXmlDocument typedResult = new TypedXmlDocument("ValidationResult", validationResult);
TypedXmlDocument typedTransaction = new TypedXmlDocument("Transaction", transaction);

System.Collections.ArrayList FactList = new System.Collections.ArrayList();
FactList.Add(typedResult);
FactList.Add(typedTransaction);

DebugTrackingInterceptor debug = new DebugTrackingInterceptor(@"D:\trace.txt");
Policy rulePolicy = new Policy("ValidateTransaction");
rulePolicy.Execute(FactList.ToArray());
rulePolicy.Dispose();

Wednesday, January 17, 2007

Passing an Array of Facts into the Rules Engine

Passing an Array of Facts into the Rules Engine (BizTalk 2004)

The last piece of the puzzle for me in working with generic messages to do away with a TON of duplication is to dynamically call a rules policy to validate outbound EDI messages.

This is some sample code I found on the blog mentioned above:

//System.Collections.ArrayList List;
sCon = "Initial Catalog=Northwind;Data Source=(local);Integrated Security=SSPI;";
con = new System.Data.SqlClient.SqlConnection(sCon);
dcNorthwind = new Microsoft.RuleEngine.DataConnection("Northwind", "ShipperCountry", con);
List.Add(dcNorthwind);


xmlDocument = msgShippingRequest;
typedXmlDocument = new Microsoft.RuleEngine.TypedXmlDocument("RoleLinkSample.ShippingRequest",xmlDocument);
policy = new Microsoft.RuleEngine.Policy("ShippingPolicy");
List.Add(typedXmlDocument);


policy.Execute(List.ToArray());
msgOutgoingShippingRequest = typedXmlDocument.Document;
policy.Dispose();
typedXmlDocument = null;
dcNorthwind = null;


This sample is based on Biztalk 2004, but should not differ in this instance for Biztalk 2006.

Tuesday, January 16, 2007

Dynamic Mapping (Transforms) in Biztalk Orchestrations

TopXML : Dynamic Mapping (Transforms) in Biztalk Orchestrations, in XmlDocument

This is how we call maps dynamically in Biztalk 2006.

tMapType = System.Type.GetType("DynamicMaps.Map_A, DynamicMaps, Version=1.0.0.0, Culture=neutral, PublicKeyToken=faed587cb93de4ea");

construct Out_Xml

{

transform (Out_Xml) = tMapType(In_Xml);

}

BizTalk Correlation of Untyped Messages

Richard Seroter - SoCal BizTalk Musings : BizTalk Correlation of Untyped Messages

This is VERY cool...

I had two choices: created fifty separate orchestrations to handle all of the types and scenarios I needed to cover, or find a way to correlate untyped (XmlDocument) messages. I searched for the latter and found this article.

public IBaseMessage Execute(IPipelineContext pc, IBaseMessage inmsg)
{
string trackCode = Convert.ToString(System.Guid.NewGuid());
inmsg.Context.Promote("TrackingID", "http://Microsoft.Demo.Customer.CustomerPropertySchema", trackCode);
return inmsg;
}

Sweet!

Wednesday, January 10, 2007

MSDN TV: Introduction to Analysis Services 2005

I watched this demo and it is really impressive how quicky analysis cubes can be created and consumed in SQL Server 2005. I haven't had the opportunity to use analysis services with SQL Server 2000, so I can't appreciate how much easier it is in 2005. However, the benefits of cubed data become apparent pretty quickly while watching this short demo.

MSDN TV: Introduction to Analysis Services 2005

SQL Server Query Performance Tuning

This article on SQL Server Query performance tuning appears to be very useful. Something to have in the toolbox.

http://www.sql-server-performance.com/statistics_io_time.asp

Create Data Insert Scripts

This link is to a stored proc that will create Insert scripts for all of the data in a sql server table. A useful little bugger...

http://vyaskn.tripod.com/code/generate_inserts.txt

How to remove xmlns attributes

How to remove xmlns attributes in html out put via copy-of

Yippie friggin doo da! I found this xsl script that strips namespaces and prefixes out of an xml document. This is going to be very useful in some Biztalk 2004 transformations that I doing.

This is what I ended up with:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="*">
<!-- remove element prefix (if any) -->
<xsl:element name="{local-name()}">
<!-- process attributes -->
<xsl:for-each select="@*">
<!-- remove attribute prefix (if any) -->
<xsl:attribute name="{local-name()}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:for-each>
<xsl:apply-templates />
</xsl:element>
</xsl:template>
</xsl:stylesheet>

BizTalk Server 2006 Business Rules and Static Methods

This is an INCREDIBLY useful trick to test your Biztalk Business Rules Engine policies. Definitely a must have for BRE development.

http://blogs.msdn.com/richardbpi/archive/2005/11/14/492489.aspx

Windows Group and User Accounts in BizTalk Server 2006

Users and Groups to setup for BTS 2006 install.

Windows Group and User Accounts in BizTalk Server 2006

Biztalk 2006 Suspended Message Routing and Error Reporting

I may need to use the code in this article very soon. I am using BTS 2006 to handle EDI transactions. When things are on the happy path, generating a 997 Ack is easy. It is when the message breaks and will not parse in the flat-file schema that it gets a little sticky. I can take these messages that have been suspended, run them through a "permissive" version of the edi flat-file schema, and then use that instance to create a 997 NAck. That is a possibility I am entertaining anyway.

Biztalk 2006 Suspended Message Routing and Error Reporting

Biztalk Send Port File Name Macros

If you ever wanted to know how to use any other file name macros other than %MessageID% here they are:

%datetime%
Coordinated Universal Time (UTC) date time in the format YYYY-MM-DDThhmmss (for example, 1997-07-12T103508).

%datetime_bts2000%
UTC date time in the format YYYYMMDDhhmmsss, where sss means seconds and milliseconds (for example, 199707121035234 means 1997/07/12, 10:35:23 and 400 milliseconds).

%datetime.tz%
Local date time plus time zone from GMT in the format YYYY-MM-DDThhmmssTZD, (for example, 1997-07-12T103508+800).

%DestinationParty%
Name of the destination party. The value comes from message the context property BTS.DestinationParty.

%DestinationPartyID%
Identifier of the destination party (GUID). The value comes from the message context property BTS.DestinationPartyID.

%DestinationPartyQualifier%
Qualifier of the destination party. The value comes from the message context property BTS.DestinationPartyQualifier.

%MessageID%
Globally unique identifier (GUID) of the message in BizTalk Server. The value comes directly from the message context property BTS.MessageID.

%SourceFileName%
Name of the file from where the File adapter read the message. The file name includes extension and excludes the file path, for example, foo.xml. When substituting this property, the File adapter extracts the file name from the absolute file path stored in the FILE.ReceivedFileName context property. If the context property does not have a value, for example, if message was received on an adapter other than File adapter, then the macro will not be substituted and will remain in the file name as is (for example, C:\Drop\%SourceFileName%).

%SourceParty%
Name of the source party from which the File adapter received the message.

%SourcePartyID%
Identifier of the source party (GUID). The value comes from the message context property BTS.SourcePartyID.

%SourcePartyQualifier%
Qualifier of the source party from which the File adapter received the message.

%time%
UTC time in the format hhmmss.

%time.tz%
Local time plus time zone from GMT in the format hhmmssTZD (for example, 124525+530).

Source:
http://www.codeproject.com/useritems/SendHandlerMacro.asp

Group Aggregation in Biztalk 2004 Maps

I had a scenario where I need to group and aggregate values in a BizTalk 2004 map based on several like fields. I put together a prototype that uses an xslt technique known as "Muenchian Grouping." The overview is that it uses an xsl:key to identify xml nodes based on specific values. Below is the code that makes up the prototype...

Source xml:

<PurchaseOrders>
<PurchaseOrder>
<From>John</From>
<To>Surrendar</To>
<PONumber>1</PONumber>
<LineItems>
<LineItem>
<PONumber>1</PONumber>
<ItemCode>ScreenCleaner</ItemCode>
<Description>Cleans computer screens</Description>
<Price>1.00</Price>
<Quantity>1</Quantity>
</LineItem>
<LineItem>
<PONumber>1</PONumber>
<ItemCode>ScreenCleaner</ItemCode>
<Description>Cleans computer screens</Description>
<Price>1.00</Price>
<Quantity>1</Quantity>
</LineItem>
<LineItem>
<PONumber>1</PONumber>
<ItemCode>ScreenCleaner</ItemCode>
<Description>Cleans computer screens type 2</Description>
<Price>1.00</Price>
<Quantity>1</Quantity>
</LineItem>
<LineItem>
<PONumber>1</PONumber>
<ItemCode>NetworkCable</ItemCode>
<Description>Computer network cable</Description>
<Price>1.00</Price>
<Quantity>1</Quantity>
</LineItem>
<LineItem>
<PONumber>1</PONumber>
<ItemCode>ScreenCleaner</ItemCode>
<Description>Cleans computer screens type 2</Description>
<Price>1.00</Price>
<Quantity>1</Quantity>
</LineItem>
<LineItem>
<PONumber>1</PONumber>
<ItemCode>ScreenCleaner</ItemCode>
<Description>Cleans computer screens type 2</Description>
<Price>1.00</Price>
<Quantity>1</Quantity>
</LineItem>
</LineItems>
</PurchaseOrder>
<PurchaseOrder>
<From>John</From>
<To>Surrendar</To>
<PONumber>2</PONumber>
<LineItems>
<LineItem>
<PONumber>2</PONumber>
<ItemCode>ScreenCleaner</ItemCode>
<Description>Cleans computer screens</Description>
<Price>1.00</Price>
<Quantity>1</Quantity>
</LineItem>
<LineItem>
<PONumber>2</PONumber>
<ItemCode>NetworkCable</ItemCode>
<Description>Computer network cable</Description>
<Price>1.00</Price>
<Quantity>1</Quantity>
</LineItem>
<LineItem>
<PONumber>2</PONumber>
<ItemCode>NetworkCable</ItemCode>
<Description>Computer network cable</Description>
<Price>1.00</Price>
<Quantity>1</Quantity>
</LineItem>
<LineItem>
<PONumber>2</PONumber>
<ItemCode>NetworkCable</ItemCode>
<Description>Computer network cable</Description>
<Price>1.00</Price>
<Quantity>1</Quantity>
</LineItem>
<LineItem>
<PONumber>2</PONumber>
<ItemCode>NetworkCable</ItemCode>
<Description>Computer network cable type 2</Description>
<Price>1.00</Price>
<Quantity>1</Quantity>
</LineItem>
</LineItems>
</PurchaseOrder>
</PurchaseOrders>

A screen-shot of the map is attached to the bottom of this post.

This is the xslt that I am running in a script functiod call-template:

<xsl:template name="POTransform">
<xsl:param name="PONumber" />
<xsl:for-each select="//LineItem[
generate-id()=generate-id(key('line-key', concat($PONumber,ItemCode,Description))[1])]">
<xsl:apply-templates select="current()" />
</xsl:for-each>
</xsl:template>
<xsl:template match="LineItem">
<xsl:variable name="LineItemList" select="//LineItem[(ItemCode = current()/ItemCode)
and (PONumber = current()/PONumber) and (Description = current()/Description)]" />
<xsl:call-template name="BuildLineItem">
<xsl:with-param name="list" select="$LineItemList" />
</xsl:call-template>
</xsl:template>
<xsl:template name="BuildLineItem">
<xsl:param name="list" />
<xsl:param name="PONumberParam" />
<xsl:element name="LineItem">
<xsl:element name="PONumber">
<xsl:value-of select="$list/PONumber" />
</xsl:element>
<xsl:element name="ItemCode">
<xsl:value-of select="$list/ItemCode" />
</xsl:element>
<xsl:element name="Description">
<xsl:value-of select="$list/Description" />
</xsl:element>
<xsl:element name="Price">
<xsl:value-of select="$list/Price" />
</xsl:element>
<xsl:element name="Quantity">
<xsl:value-of select="sum($list/Quantity)" />
</xsl:element>
</xsl:element>
</xsl:template>
<xsl:key name="line-key" match="LineItem" use="concat(PONumber,ItemCode,Description)" />

And finally, this is the output xml:

<PurchaseOrders>
<PurchaseOrder>
<From>John</From>
<To>Surrendar</To>
<PONumber>1</PONumber>
<LineItems>
<LineItem>
<PONumber>1</PONumber>
<ItemCode>ScreenCleaner</ItemCode>
<Description>Cleans computer screens</Description>
<Price>1.00</Price>
<Quantity>2</Quantity>
</LineItem>
<LineItem>
<PONumber>1</PONumber>
<ItemCode>ScreenCleaner</ItemCode>
<Description>Cleans computer screens type 2</Description>
<Price>1.00</Price>
<Quantity>3</Quantity>
</LineItem>
<LineItem>
<PONumber>1</PONumber>
<ItemCode>NetworkCable</ItemCode>
<Description>Computer network cable</Description>
<Price>1.00</Price>
<Quantity>1</Quantity>
</LineItem>
</LineItems>
</PurchaseOrder>
<PurchaseOrder>
<From>John</From>
<To>Surrendar</To>
<PONumber>2</PONumber>
<LineItems>
<LineItem>
<PONumber>2</PONumber>
<ItemCode>ScreenCleaner</ItemCode>
<Description>Cleans computer screens</Description>
<Price>1.00</Price>
<Quantity>1</Quantity>
</LineItem>
<LineItem>
<PONumber>2</PONumber>
<ItemCode>NetworkCable</ItemCode>
<Description>Computer network cable</Description>
<Price>1.00</Price>
<Quantity>3</Quantity>
</LineItem>
<LineItem>
<PONumber>2</PONumber>
<ItemCode>NetworkCable</ItemCode>
<Description>Computer network cable type 2</Description>
<Price>1.00</Price>
<Quantity>1</Quantity>
</LineItem>
</LineItems>
</PurchaseOrder>
</PurchaseOrders>

One thing to note about this solution is that it does require a parent-child relationship to be present in the actual xml data. Often, this relationship is implied in xml by the nesting structure. In such a case, this solution would not be able to find the proper context for the LineItem nodes that are to be rolled up. This example uses the PONumber node to define the parent-child relationship. Including this data in the source xml data in both the parent and child nodes allows that context to be defined so that all LineItems on the same PO can be aggregated.

Here is a screen-shot of the map I used:

How much of C# syntax can you use in an Expression shape?

In case you were wondering why you are not able to do certain operations in the BizTalk Expression shape within an Orchestration, here is the answer:

How much of C# syntax can you use in an Expression shape?

The bottom line is that the language under the hood is not C#, but is XLANG/S which cannot support certain tasty morsels that C# developers know and love (for, foreach, (++,--), etc. Big frowny face for that one!

Here's another link that goes into even more detail:

http://geekswithblogs.net/cyoung/articles/3820.aspx

Using App.Config Settings in BizTalk 2004

This is an example of how to use app.config settings in a BizTalk 2004 Orchestration.
First, you must setup the configuration section that you want to use. This is an example of what this looks like:

<!--This is an example of setting up your configuration section-->
<configuation>
<configSections>
<section name='MyConfigSection' type='System.Configuration.NameValueSectionHandler' />
</configSections>

<MyConfigSection>
<add key='MyKey' value='MyValue' />
</MyConfigSection>
</configuration>

Then, create an orchestration variable of type System.Collections.Specialized.NameValueCollection (I'll call it varConfigHandler)

This is an example of using the varConfigHandler in an expression shape:

// varConfigHandler has to be instantiated and bound to the config section we are interested in
// Notice that the result of the GetConfig function call is being cast into a NameValueCollection
varConfigHandler = new System.Collections.Specialized.NameValueCollection((
System.Collections.Specialized.NameValueCollection)
System.Configuration.ConfigurationSettings.GetConfig("MyConfigSection"));

// Now, we can access keys in the config section
varConfigHandler.Get("MyKey");

For deployment, copy the configSections/section and MyConfigSection into the config file for the BizTalk Service which is located at:

C:\Program Files\Microsoft BizTalk Server 2004\BTSNTSvc.exe.config

I'm Back!

Okay, the new version of Blogger is waaaaay better than the previous version. In fact, I like it a lot better than MSN Spaces...so I'm coming back!

Over the next few weeks I'll be going through the painful process of moving my posts over from my Spaces blog.

Yay Blogger! :)