BizTalk Tip : Number of Orchestrations Tracking Data Query

Quick query to give number of orchestration instances over the last week. Grouped by orchestration name.

USE [BizTalkDTADb]

SELECT
	bts_Orchestration.nvcFullName,
	count(bts_Orchestration.nvcFullName) 'COUNT'
FROM
	dta_DebugTrace with (READPAST) JOIN dta_ServiceInstances on dta_DebugTrace.uidServiceInstanceID = dta_ServiceInstances.uidServiceInstanceId
								   LEFT JOIN BizTalkMgmtDb.dbo.bts_Orchestration on dta_ServiceInstances.uidServiceId = bts_Orchestration.uidGUID
WHERE 
	dta_ServiceInstances.dtEndTime >= DATEADD(WEEK, -1, GETDATE())
GROUP BY bts_Orchestration.nvcFullName
ORDER BY 'COUNT' desc
Advertisements
Posted in BizTalk Server, SQL Server | Leave a comment

BizTalk : Clone Message Disassembler Pipeline Component

A custom disassembler to clone inbound messages.

To run the sample create a class library with references to,

  • Microsoft.BizTalk.Pipeline.dll
  • Microsoft.BizTalk.Streaming.dll
  • Microsoft.XLANGs.BaseTypes.dll

Sign, compile, and gac the class library with the below code.  Note how the message is being cloned and added to the queue.

using System;
using System.IO;
using System.Xml;
using System.Linq;
using System.Resources;
using System.Reflection;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.ComponentModel;
using System.Collections.Generic;
using Microsoft.BizTalk.Streaming;
using System.Runtime.InteropServices;
using Microsoft.BizTalk.Message.Interop;
using Microsoft.BizTalk.Component.Interop;

namespace PipelineComponents
{
    [ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
    [System.Runtime.InteropServices.Guid("eeff154c-e26b-8888-6666-bfccc0eb3448")]
    [ComponentCategory(CategoryTypes.CATID_DisassemblingParser)]
    public class ClonePipelineComponent : Microsoft.BizTalk.Component.Interop.IDisassemblerComponent, IBaseComponent, IPersistPropertyBag, IComponentUI
    {
        #region Variables

        System.Collections.Queue queueOutMsgs = new System.Collections.Queue();

        #endregion

        #region IPersistPropertyBag

        public void GetClassID(out Guid classID)
        {
            classID = new Guid("eeff154c-e26b-8888-6666-bfccc0eb3448");
        }

        public void InitNew()
        {

        }

        IEnumerator IComponentUI.Validate(object projectSystem)
        {
            return new ArrayList(0).GetEnumerator();
        }

        public void Load(IPropertyBag propertyBag, int errorLog)
        {
            
        }

        public void Save(IPropertyBag propertyBag, bool clearDirty, bool saveAllProperties)
        {
            
        }

        #endregion

        #region IDisassemblerComponent Members

        public void Disassemble(IPipelineContext pContext, IBaseMessage pInMsg)
        {
            Stream inMsgStream = pInMsg.BodyPart.GetOriginalDataStream();

            if (!inMsgStream.CanSeek)
            {
                ReadOnlySeekableStream seekableStream = new ReadOnlySeekableStream(inMsgStream);
                pContext.ResourceTracker.AddResource(seekableStream);
                inMsgStream = seekableStream;
            }

            // Hardcoded here for sample.  Add this as a BRE rule or pipeline component property
            int numberOfClones = 2;

            for(int i=0; i <= numberOfClones; i++)
            {
                inMsgStream.Seek(0, SeekOrigin.Begin);

                // Clone the input message
                IBaseMessage outMsg;

                outMsg = pContext.GetMessageFactory().CreateMessage();
                outMsg.AddPart("Body", pContext.GetMessageFactory().CreateMessagePart(), true);
                outMsg.BodyPart.Data = inMsgStream;
                outMsg.Context = PipelineUtil.CloneMessageContext(pInMsg.Context);

                string contextPropertyValue = "YourSampleContextPropertyValue";

                // Promote or write any context properties here
                outMsg.Context.Promote("YourContextPropertyName", "http://YourContextPropertyNamespace", contextPropertyValue);

                // Add cloned messages to the queue
                queueOutMsgs.Enqueue(outMsg);
            }
        }

        public IBaseMessage GetNext(IPipelineContext pContext)
        {
            if (queueOutMsgs.Count > 0)
            {
                IBaseMessage outMsg = (IBaseMessage)queueOutMsgs.Dequeue();

                Stream stream = outMsg.BodyPart.GetOriginalDataStream();
 
                if (!stream.CanSeek)
                {
                    ReadOnlySeekableStream seekableStream = new ReadOnlySeekableStream(stream);
                    pContext.ResourceTracker.AddResource(seekableStream);
                    stream = seekableStream;
                }
 
                stream.Seek(0, SeekOrigin.Begin);

                return outMsg;
            }
            else
                return null;
        }

        #endregion

        #region IComponentUI Properties

        [Browsable(false)]
        public string Description
        {
            get
            {
                return "Clone Pipeline Component";
            }
        }

        [Browsable(false)]
        IntPtr IComponentUI.Icon
        {
            get
            {
                return IntPtr.Zero;
            }
        }

        [Browsable(false)]
        public string Name
        {
            get
            {
                return "Clone Pipeline Component";
            }
        }

        [Browsable(false)]
        public string Version
        {
            get
            {
                return Assembly.GetExecutingAssembly().GetName().Version.ToString(2);
            }
        }

        #endregion

    }
}
Posted in BizTalk Server | Leave a comment

ESB Toolkit : Create Custom Itinerary Resolver

The below is a demonstration of a custom Itinerary Resolver.  i.e. instead of using the Itinerary-STATIC or Itinerary-BRE resolver we are developing our own here.  Basically we are creating a component to access a custom itinerary fact store. To get this sample code running create a class library and then add a reference to,

  • Microsoft.BizTalk.Pipeline.dll
  • Microsoft.Practices.ESB.Configuration.dll
  • Microsoft.Practices.ESB.Resolver.dll
  • Microsoft.Practices.ESB.Resolver.Facts.dll
  • Microsoft.Practices.ESB.Resolver.Itinerary.dll
  • Microsoft.Practices.ESB.Itinerary.DataAccess.dll
  • Microsoft.Practices.ESB.Resolver.Itinerary.Facts.dll
  • Microsoft.XLANGs.BaseTypes.dll

Sign, compile, and GAC the class library with the below code.  Note the line where the string variable itineraryName is assigned.  Replace this with a call to your repository or alternate rules engine.

using System;
using System.Xml;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.XLANGs.BaseTypes;
using System.Collections.Generic;
using Microsoft.Practices.ESB.Resolver;
using Microsoft.BizTalk.Message.Interop;
using Microsoft.BizTalk.Component.Interop;
using Microsoft.Practices.ESB.Resolver.Facts;
using Microsoft.Practices.ESB.Resolver.Itinerary.Facts;
using Microsoft.Practices.ESB.Resolver.Itinerary.DataAccess;
using Microsoft.Practices.ESB.Resolver.Itinerary.Facts.Repository;

namespace ItineraryResolvers
{
    public class SampleItineraryResolver : IResolveProvider
    {
        #region Variables

        private List<IFactTranslator> factTranslatorList;
        private static System.Runtime.Caching.ObjectCache cache;

        #endregion 

        #region Constructors

        public SampleItineraryResolver()
        {
        }

        public SampleItineraryResolver(Microsoft.Practices.ESB.Configuration.Resolver resolverConfig)
        {
            IRepositoryProvider repositoryProvider = new SqlRepositoryProvider(ResolverConfigHelper.ReadResolverConfigByKey(resolverConfig, "connectionStringName"),
                                                                                    ResolverConfigHelper.ReadResolverConfigByKey(resolverConfig, "cacheManagerName"), 
                                                                                    ResolverConfigHelper.ReadResolverConfigByKey(resolverConfig, "cacheTimeout"));

            this.factTranslatorList = new List<IFactTranslator>(2);
            this.factTranslatorList.Add(new DefaultFactTranslator());
            this.factTranslatorList.Add(new ItineraryFactTranslator(repositoryProvider));
        }

        #endregion

        #region Public Methods

        public Dictionary<string, string> Resolve(string config, string resolver, IBaseMessage message, IPipelineContext pipelineContext)
        {
            #region Validation

            if (string.IsNullOrEmpty(config))
            {
                throw new ArgumentNullException("config");
            }
            if (string.IsNullOrEmpty(resolver))
            {
                throw new ArgumentNullException("resolver");
            }
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }
            if (pipelineContext == null)
            {
                throw new ArgumentNullException("pipelineContext");
            }

            #endregion

            Dictionary<string, string> resolverDictionary = new Dictionary<string, string>();
            Resolution resolution = new Resolution();

            ResolverMgr.SetContext(resolution, message, pipelineContext);

            string itineraryName = "Itineraries1"; // Replace hardcoded name with read on repository
            string[] facts = itineraryName.Split(new char[]{','}, StringSplitOptions.RemoveEmptyEntries);
            string resolverConfig = string.Empty;

            if (facts.Length == 1)
            {
                resolverConfig = "ITINERARY-CUSTOM:\\\\name=" + facts[0];
            }
            else
            {
                resolverConfig = "ITINERARY-CUSTOM:\\\\name=" + facts[0] + ";Version=" + facts[1];
            }

            Dictionary<string, string> dictionary = this.ResolveItinerary(resolverConfig, resolver, resolution);

            resolverDictionary["Resolver.Itinerary"] = dictionary["Resolver.Itinerary"];
            resolverDictionary["Resolver.ItineraryName"] = dictionary["Resolver.ItineraryName"];
            resolverDictionary[ResolverKeys.InterchangeId] = dictionary[ResolverKeys.InterchangeId];

            return resolverDictionary;
        }

        public Dictionary<string, string> Resolve(ResolverInfo resolverInfo, XLANGMessage message)
        {
            throw new Exception("Not Implemented.");
        }

        Dictionary<string, string> IResolveProvider.Resolve(string config, string resolver, XmlDocument message)
        {
            throw new Exception("Not Implemented.");
        }

        #endregion

        #region Private Methods

        private Dictionary<string,string> ResolveItinerary(string config, string resolver, Resolution resolution)
        {
            Dictionary<string, string> facts = ResolverMgr.GetFacts(config, resolver);
            ItineraryFact fact = new ItineraryFact{ Name = ResolverMgr.GetConfigValue(facts, true, "name")};
            Dictionary<string, string> result = new Dictionary<string, string>();

            string version = ResolverMgr.GetConfigValue(facts, false, "version");

            if (!string.IsNullOrEmpty(version))
            {
                fact.SetVersion(version);
            }

            object[] objArray = new object[] { resolution, fact, facts };

            foreach (IFactTranslator translator in this.factTranslatorList)
            {
                translator.TranslateFact(objArray, result);
            }
            return result;
        }

        #endregion
    }
}

Register the new Itinerary resolver with ESBT by adding it to the esb.config as per below.

      <resolver name="ITINERARY-CUSTOM" type="ItineraryResolvers.SampleItineraryResolver, ItineraryResolvers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3a8d04cd32444555">
        <resolverConfig>
          <add name="connectionStringName" value="ItineraryDb" />
          <add name="cacheTimeout" value="120" />
          <add name="cacheManagerName" value="Itinerary Cache Manager" />
        </resolverConfig>
      </resolver>

Now configure the Itinerary Selector component to use the ITINERARY-CUSTOM resolver and job done!

Screen Shot 2015-07-23 at 10.52.49 pm

Posted in BizTalk Server | Leave a comment

ESBT 2.3 Missing Itinerary Designer

After installing ESBT 2.3 with BizTalk 2013 R2 and Visual Studio 2013 the itinerary designer template will be dropped from Visual Studio.  Easy fix is to tell Visual Studio to rebuild the template from the visual studio packages by executing the below from the Visual Studio Tools command prompt.

image 

Start Visual Studio and the templates will be reinitialized.

image

Hey presto, BizTalk ESB Itinerary Designer

image

Posted in BizTalk Server | Leave a comment

ImmDoc.NET

Handy light weight tool for documenting projects. On this last project I’ve been running this tool over my prototypes and using that to help with some heavy lifting in my design documentation.

http://immdocnet.codeplex.com/

Posted in .NET, Tools | Leave a comment

C# String to SByte[] to String

        private static string SByteArrayToString(sbyte[] sbytes)
        {
            //Convert sbyte[] to byte[]
            byte[] byteData = Array.ConvertAll(sbytes, (a) => (byte)a);
            return Encoding.ASCII.GetString(byteData);
        }

        private static sbyte[] StringToSByte(string value)
        {
            // convert string to byte array
            byte[] bytes = Encoding.ASCII.GetBytes(value);

            // convert byte array to sbyte array
            sbyte[] sbytes = new sbyte[bytes.Length];
            for (int i = 0; i < bytes.Length; i++)
                sbytes[i] = (sbyte)bytes[i];

            return sbytes;
        }
Posted in .NET, BizTalk Server | Leave a comment

Generate XSD from .NET Class within IDE

Been using XSD.exe for years from the command line to generate XSD.  Recently I decided to add it to the Visual Studio IDE so I can simply click the class file in solution explorer and generate an XSD.

  1. Open Visual Studio and go to Tools->External Tools
  2. Click Add and name the menu item “Class to XSD”
  3. Add the command, browse for XSD.exe
  4. Add arguments, $(BinDir)$(TargetName).dll /outputdir:$(ItemDir) /type:$(ItemFileName)

That’s it!  You should have something looking like the below.  To use it go to your .cs file in solution explorer and click it.  Then go to Tool->Class to XSD.  The .xsd files will be created in the same folder as your classes.

Screen Shot 2015-06-06 at 2.46.00 pm

Posted in .NET, BizTalk Server, Tools | 1 Comment