Infosys Microsoft Alliance and Solutions blog

« Cross Thread UI control access | Main | BizTalk 2006 Documentation »

BizTalk - String manipulation using Business Rules Engine

Some time back while working on a project we had requirement to do input data cleansing. The input would be a known XML format and could come from know sources. However each source could have used a different string representation than a standard one and hence it was required to fix this prior to working with the XML. For example we would want the color to be represented as "green", while the input could contain GREEN, GRN, grn etc.

There were some common conversions which were to be done for any source. However some conversions were only to be done for specific sources and additionally support was required to add new sources at any time without rebuilding the application. We discussed and decided that Mapping won't work since, one we needed a generic string replacement as against specific XML node manipulation and two we wanted dynamic addition of sources.

What follows is a discussion of the solution that we implemented. I would like to acknowledge the support from my colleague Jitendra Pal Thethi in coming up with this solution and the code base. Considering the different string manipulations required for each source and ability to dynamically add new sources, we decided to use Business Rules Engine (BRE) along with a custom .net component that do the actual execution. Following are some sample rules that we built for this functionality. The first one was to handle the generic case i.e. the rule that will run for all sources.

IF
    Conditions
        SourceName is not equal to ""
THEN
    Actions
        Replace GRN with green
        Replace string1 with string2
        Replace string3 with string4

For a specific source, the Conditions part was altered to as below, while the actions were written in similar manner. Only the values of the strings to replace were altered as required.

IF
    Conditions
        SourceName is equal to SourceA

At any given time a new rule could be added for a new source as required and when deployed, the new policy will be picked up and be used and thus allowly easy dynamic addition of new source handling. 

The final rule to trigger the actual string replacement was something like this

IF
    Conditions
        1 is equal to 1
THEN
    Perform ReplaceAll

The condition of 1 equal to 1 forced the rule to be always executed. This can be optimized by looking up the count of strings identified for replacing. If the count is 0, we can skip executing any further code. However since BRE loads all facts and checks them upfront to build the agenda, if we did something like StringCollection.Count, it would return 0 always since at the start of execution there aren't any strings yet added. This means that even if we later add strings to the collection, the rule will still not fire since it never got added to the agenda. This can be easily addressed by doing an Assert to tell BRE that a fact has been updated. However this is also easily implemented as part of our custom .net component so we left the rule simple.

As I mentioned earlier, we also had written a custom .net component to do the actual execution. The SourceName, Replace and ReplaceAll as used in rules above are vocabularies built over this class. To capture the string values that represent the source and destination, we created a custom class as below

    [Serializable]
    public class ReplaceInfo
    {
        private string sourceString;

        public string Source
        {
            get { return sourceString; }
            set { sourceString = value; }
        }

        private string destString;

        public string Target
        {
            get { return destString; }
            set { destString = value; }
        }
    }

This class was then used in our Entity class that had a List collection to store the ReplaceInfo type. Part of this Entity class is shown below. Other than this it also had a private XmlDocument member that represented the input XML message.

    [Serializable]
    public class Entity
    {
        private XmlDocument doc;

        public XmlDocument MessageData
        {
            get { return doc; }
            set { doc = value; }
        }

        private string providerField;

        public string SourceProvider
        {
            get { return providerField; }
            set { providerField = value; }
        }

        private List<ReplaceInfo> listField = new List<ReplaceInfo>();

        public List<ReplaceInfo> ReplaceStringCollection
        {
            get { return listField; }
        }
    ...
    ...
    ...
    }

The SourceProvider property of the Entity class, as shown above, returned the name of the current Source and it was on the get accessor of this the SourceName vocabulary was built.  We then need a class to execute the strings stored in the Entity class and also add strings to be replaced to the list collection in the class. This was done using another class as below

    [Serializable]
    public class RuleExecutor
    {

        public void AddString(string strFrom, string strTo)
        {
            ReplaceInfo r = new ReplaceInfo();
            r.Source = strFrom;
            r.Target = strTo;
            entity.ReplaceStringCollection.Add(r);
        }

        public void ReplaceAll()
        {
            StringBuilder sb = new StringBuilder(entity.MessageData.InnerXml);

            foreach (ReplaceInfo rInfo in entity.ReplaceStringCollection)
            {
                sb.Replace(rInfo.Source, rInfo.Target);
            }
           
            //done with the string replacements.. put the modified XML back in the
            //property variable from where the orchestration will pick it up
            entity.MessageData.InnerXml = sb.ToString();
        }
    ...
    ...
    ...
    }

The AddString method of this class is set as the Replace vocabular that is used as part of the Actions of the rules mentioned earlier and the ReplaceAll method is set as the ReplaceAll vocabulary. Since BRE offers setting a more user friendly display name, we set the "AddString" .net class method as "Replace {0} with {1}", as seen in the rule snipper earlier.

This way we built an easy mechanism to manipulate strings and also had the ability to add more sources at run time. To test the rules we also built fact creator by implementing the IFactCreator interface and providing implementations for CreateFacts and GetFactTypes methods. 

Comments

Hi.

I have written a custom .net component. But I have a problem. When using a method in a policy (that only returns a string), nothing happens. I cannot find out the reason. No error messages etc. I guess it is possible to use methods that returns something? Is it a certain way to write the custom component/class library?

Thanks

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

Please key in the two words you see in the box to validate your identity as an authentic user and reduce spam.

Subscribe to this blog's feed

Follow us on

Blogger Profiles

Infosys on Twitter