Thursday, February 27, 2014

Use extension methods for enum

Create below custom attribute class, which will be used  for enum.

public class EnumDescAttribute : Attribute
    {

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="EnumDescAttribute"/> class.
        /// </summary>
        /// <param name="description">The description.</param>
        public EnumDescAttribute(string description)
        {
            Description = description;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the description.
        /// </summary>
        /// <value>
        /// The description.
        /// </value>
        public string Description { get; set; }

        #endregion
    }

Sample Enum:

public enum QualifierType
    {
        [EnumDescAttribute("QQ")]
        SubAccount,
        [EnumDescAttribute("AA")]
        Account,
        [EnumDescAttribute("BB")]
        LegacyDivision,
        [EnumDescAttribute("CC")]
        DateRange
    }

Create below Extension class

public static class EnumExtensions
    {
        #region Public methods

        /// <summary>
        /// Gets the description attribute.
        /// </summary>
        /// <param name="en">The en.</param>
        /// <returns></returns>
        public static string GetAttributeValue(this Enum en)
        {
            string returnValue = en.ToString();
            Type type = en.GetType();

            //MemberInfo[] memInfo = type.GetMember(en.ToString());
            //if (memInfo != null && memInfo.Length > 0)
            //{
            //    object[] attributes = memInfo[0].GetCustomAttributes(typeof(EnumDescAttribute), false);

            //    if (attributes != null && attributes.Length > 0)
            //    {
            //        returnValue = ((EnumDescAttribute)attributes[0]).Description;
            //    }

            //}
            EnumDescAttribute attribute = GetAttribute<EnumDescAttribute>(en);
            if (attribute != null)
            {
                returnValue = attribute.Description;
            }
            return returnValue;
        }

        /// <summary>
        /// Converts to enum.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public static T ConvertToEnum<T>(this string value)
        {
            T returnValue = default(T);

            returnValue = (T)Enum.Parse(typeof(T), value, true);

            return returnValue;
        }

        #endregion

        #region Private methods

        /// <summary>
        /// Gets the attribute.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        private static T GetAttribute<T>(this Enum value) where T : Attribute
        {
            Type type = value.GetType();
            string name = Enum.GetName(type, value);
         
            return type.GetField(name)
                        .GetCustomAttributes(false)
                        .OfType<T>()
                        .FirstOrDefault();
        }

        #endregion
    }


Get enum attribute value:

static void Main(string[] args)
        {
            Console.WriteLine(consts.Enumerations.QualifierType.Account.GetAttributeValue());
            Console.ReadLine();
         
            string value ="Account";
            Console.WriteLine(value.ConvertToEnum<consts.Enumerations.QualifierType>().ToString());
            Console.ReadLine();
        }

Wednesday, February 12, 2014

Update all items in a collection using Linq

collection = collection.Select(item => {item.PropertyToSet = value; return item;}).ToList();

or

users.ToList().ForEach(u =>
                      {
                         u.property1 = value1;
                         u.property2 = value2;
                      });

Got "Specified method is not supported" error when I try to use the xpathnavigator.setvalue()

This error occurred because of my XPathNavigator object created using XPathDocument object and it's read-only. So, XPathNavigator object has to be created form XMLDocument to edit the values using SetValue().


XPathDocument document = new XPathDocument(xmlStream);
XPathNavigator xPathNavigator = document.CreateNavigator();

Here we can get the "Specified method is not supported" error When I try to use the Setvalue() method.

To avoid this error, create navigator object using the XmlDocument .

XmlDocument doc = new XmlDocument();
doc.Load(@"{file-uri}"); 
XPathNavigator xPathNavigator = doc.CreateNavigator();

Friday, February 7, 2014

Get Unique values at document level using xpath


I have used preceding-sibling and following-sibling to get the unique skill values from the below XML message.

XmlDocument doc = new XmlDocument();
doc.Load(@"{file-uri}");

MemoryStream xmlStream = new MemoryStream();
            doc.Save(xmlStream);

            xmlStream.Flush();//Adjust this if you want read your data
            xmlStream.Position = 0;

            //XmlReader reader = XmlReader.Create(doc.OuterXml);
            //XPathDocument document = new XPathDocument(reader);
            XPathDocument document = new XPathDocument(xmlStream);
            XPathNavigator xPathNavigator = document.CreateNavigator();

            xPathNavigator.MoveToRoot(); // Move to the root element.
            if (xPathNavigator.HasChildren)
            {
                xPathNavigator.MoveToFirstChild();
            }
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(new NameTable());
          nsmgr.AddNamespace("ns0:", "http://www.RVRCompany.com/en/core/employee");

XPathNodeIterator nodIterator = xPathNavigator.Select("//ns0:Employee/ns0:Project/ns0:Skills/ns0:Skill/ns0:SkillName[not(../../../../following-sibling::ns0:Employee/ns0:Project/ns0:Skills/ns0:Skill/ns0:SkillName = .) and not(preceding-sibling::ns0:SkillName=.)]",namespaceManager);

Console.WriteLine("Unique values **********************************************");
            while (nodIterator.MoveNext())
            {
                Console.WriteLine(nodIterator.Current.Value);
            }
            Console.ReadLine();

Sample XML:

<ns0:UpdateEmployeesRequest xmlns:ns0="http://www.RVRCompany.com/en/core/employee">
<ns0:EmployeeDetails>
<ns0:Employee>
<ns0:EmpID>1</ns0:EmpID>
<ns0:Project>
<ns0:ProjectName>PROJ1</ns0:ProjectName>
<ns0:Skills>
<ns0:Skill>
<ns0:SkillType>MS</ns0:SkillType>
<ns0:SkillName>.Net</ns0:SkillName>
</ns0:Skill>
<ns0:Skill>
<ns0:SkillType>MS</ns0:SkillType>
<ns0:SkillName>BizTalk</ns0:SkillName>
</ns0:Skill>
<ns0:Skill>
<ns0:SkillType>MS</ns0:SkillType>
<ns0:SkillName>.Net</ns0:SkillName>
</ns0:Skill>
</ns0:Skills>
</ns0:Project>
</ns0:Employee>
<ns0:Employee>
<ns0:EmpID>2</ns0:EmpID>
<ns0:Project>
<ns0:ProjectName>PROJ2</ns0:ProjectName>
<ns0:Skills>
<ns0:Skill>
<ns0:SkillType>MS</ns0:SkillType>
<ns0:SkillName>.Net</ns0:SkillName>
</ns0:Skill>
<ns0:Skill>
<ns0:SkillType>MS</ns0:SkillType>
<ns0:SkillName>BizTalk</ns0:SkillName>
</ns0:Skill>
<ns0:Skill>
<ns0:SkillType>MS</ns0:SkillType>
<ns0:SkillName>.Net</ns0:SkillName>
</ns0:Skill>
<ns0:Skill>
<ns0:SkillType>Sun Micros</ns0:SkillType>
<ns0:SkillName>Java</ns0:SkillName>
</ns0:Skill>
</ns0:Skills>
</ns0:Project>
</ns0:Employee>
<ns0:Employee>
<ns0:EmpID>3</ns0:EmpID>
<ns0:Project>
<ns0:ProjectName>PROJ2</ns0:ProjectName>
<ns0:Skills>
<ns0:Skill>
<ns0:SkillType>MS</ns0:SkillType>
<ns0:SkillName>VB6</ns0:SkillName>
</ns0:Skill>
<ns0:Skill>
<ns0:SkillType>MS</ns0:SkillType>
<ns0:SkillName>.Net</ns0:SkillName>
</ns0:Skill>
<ns0:Skill>
<ns0:SkillType>MS</ns0:SkillType>
<ns0:SkillName>SQL Server</ns0:SkillName>
</ns0:Skill>
<ns0:Skill>
<ns0:SkillType>MS</ns0:SkillType>
<ns0:SkillName>IIS</ns0:SkillName>
</ns0:Skill>
<ns0:Skill>
<ns0:SkillType>Sun Micros</ns0:SkillType>
<ns0:SkillName>Linux</ns0:SkillName>
</ns0:Skill>
</ns0:Skills>
</ns0:Project>
</ns0:Employee>
<ns0:Employee>
<ns0:EmpID>3</ns0:EmpID>
<ns0:Project>
<ns0:ProjectName>PROJ2</ns0:ProjectName>
<ns0:Skills>
<ns0:Skill>
<ns0:SkillType>MS</ns0:SkillType>
<ns0:SkillName>VB6</ns0:SkillName>
</ns0:Skill>
<ns0:Skill>
<ns0:SkillType>MS</ns0:SkillType>
<ns0:SkillName>IIS</ns0:SkillName>
</ns0:Skill>
<ns0:Skill>
<ns0:SkillType>Sun Micros</ns0:SkillType>
<ns0:SkillName>Linux</ns0:SkillName>
</ns0:Skill>
<ns0:Skill>
<ns0:SkillType>Sun Micros</ns0:SkillType>
<ns0:SkillName>Tomcat</ns0:SkillName>
</ns0:Skill>
<ns0:Skill>
<ns0:SkillType>Sun Micros</ns0:SkillType>
<ns0:SkillName>BizTalk</ns0:SkillName>
</ns0:Skill>
</ns0:Skills>
</ns0:Project>
</ns0:Employee>
</ns0:EmployeeDetails>

</ns0:UpdateEmployeesRequest>

Wednesday, January 22, 2014

Programmatically Enable/Disable Receive pipeline


We can achieve this functionality using the  "Microsoft.BizTalk.ExplorerOM" component.

Add reference "Microsoft.BizTalk.ExplorerOM" component to your application.

BtsCatalogExplorer bceExplorer = new BtsCatalogExplorer();
//Edit the following connection string to point to the correct database and server
bceExplorer.ConnectionString = "Integrated Security=SSPI;database=BizTalkMgmtDb;server=localhost";

public bool SetReceiveLocationState(string receivePortName, bool stateValue)
{
            bool returnValue = false;
            try
            {
                ReceivePort receivePort = bceExplorer.ReceivePorts[receivePortName];
                receivePort.ReceiveLocations.Cast<ReceiveLocation>().ToList().ForEach(receiveLocation => receiveLocation.Enable = stateValue);

                bceExplorer.SaveChanges();
                returnValue = true;
            }
            catch (Exception e)
            {
                System.Diagnostics.EventLog.WriteEntry("SetReceiveLocationState", e.Message);
                bceExplorer.DiscardChanges();
                returnValue = false;
            }
            return returnValue;
        }

Programmatically (Dynamically) change the properties of a Receive Location


We can update the properties of a File adapter Receive Location using the Microsoft.BizTalk.ExplorerOM (from {BizTalkInstallation}\DeveloperTools) and I refereed useful article from MSDN for my development.

   We have a requirement to programmatically(dynamically) change the File Mask property of the File receive location.
   The following code only deals with a File Mask property that can be changed in the File receive location.
It accepts few things as input, we accept the port name, which receive location you want to change, file mask and it will change the file mask property in the receive location.


Add reference "Microsoft.BizTalk.ExplorerOM" component to your application.

I have written below as per the MSDN article and this trick didn't worked for me.

BtsCatalogExplorer bceExplorer = new BtsCatalogExplorer();
//Edit the following connection string to point to the correct database and server
bceExplorer.ConnectionString = "Integrated Security=SSPI;database=BizTalkMgmtDb;server=localhost";

public bool UpdateReceiveLocationFileMask(string receivePortName, string receiveLocationName, string fileMask)
{
            bool returnValue = false;
            string transportData = string.Empty;
            XmlDocument doc = null;
            XmlNode root = null;
            XmlNode fileMaskNode = null;
            try
            {
                if (!string.IsNullOrEmpty(fileMask))
                {
                    ReceivePort receivePort = bceExplorer.ReceivePorts[receivePortName];
                    ReceiveLocation receiveLocation = receivePort.ReceiveLocations.Cast<ReceiveLocation>().Where(item => item.Name == receiveLocationName).FirstOrDefault();

                    if (receiveLocation != null)
                    {                        
                        transportData = receiveLocation.TransportTypeData;
                        doc = new XmlDocument();
                        doc.LoadXml(transportData);
                        root = doc.DocumentElement;
                        fileMaskNode = root.SelectSingleNode("FileMask");

                        if (fileMaskNode != null)
                        {
                            fileMaskNode.InnerText = fileMask;
                            receiveLocation.TransportTypeData = doc.OuterXml;
                            bceExplorer.SaveChanges();
                            returnValue = true;
                        }
                        bceExplorer.SaveChanges();
                        returnValue = true;
                    }
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.EventLog.WriteEntry("UpdateReceiveLocationFileMask", e.Message);
                bceExplorer.DiscardChanges();
                returnValue = false;
            }

            return returnValue;


The above code didn't worked, i have used Address property of the receive location and this trick worked for me.

public bool UpdateReceiveLocationFileMask(string receivePortName, string receiveLocationName, string fileMask)
{
            bool returnValue = false;
            string transportData = string.Empty;
            XmlDocument doc = null;
            XmlNode root = null;
            XmlNode fileMaskNode = null;
            try
            {
                if (!string.IsNullOrEmpty(fileMask))
                {
                    ReceivePort receivePort = bceExplorer.ReceivePorts[receivePortName];
                    ReceiveLocation receiveLocation = receivePort.ReceiveLocations.Cast<ReceiveLocation>().Where(item => item.Name == receiveLocationName).FirstOrDefault();

                    if (receiveLocation != null)
                    {
                        receiveLocation.Address = Path.Combine(Path.GetDirectoryName(receiveLocation.Address), fileMask);                        
                        bceExplorer.SaveChanges();
                        returnValue = true;
                    }
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.EventLog.WriteEntry("UpdateReceiveLocationFileMask", e.Message);
                bceExplorer.DiscardChanges();
                returnValue = false;
            }

            return returnValue;
}

Friday, January 17, 2014

Property Promotion inside Orchestration


Properties get promoted within BizTalk at different places, Example: some of the properties gets promoted by Adapters, Pipelines Components, Messaging Engine, etc.

    In custom pipeline components, developers can use either IBaseMessageContext.Write to write context properties or IBaseMessageContext.Promote to promote context properties. The basic difference between writing and promoting properties are, properties that are written cannot be used for message routing, whereas properties that are promoted can be used for message routing.

Below is the sample for promoting properties within Orchestration is:
    MSG_OUT(ProjectNameSpace.PropertySchema.PropertyName) = "XXX"

If we look at the outgoing message context, the above prompted property will not promote and it would be in the "NotPromoted" state.


Please follow the below instructions to promote your property within the orchestration:

    In BizTalk we have a Correlation concept, basically which routes the response messages to the correct running orchestration instance that initiated the request message. Within Orchestration we use Correlation Set and Correlation type to archive this type of instance routing.

Correlation type is nothing but a set of Properties and Correlation Set is based on Correlation type and its a set of properties with specific values. When we "Initialize a Correlation set" within orchestration, the orchestration instance automatically promotes those properties in Correlation set into the message context.

We can use this mechanism to promote properties and there is no need to do a follow up of the Correlations sets we initialized, and it NOT going to create unnecessary subscriptions.