Friday, March 23, 2012

BizTalk Archiving: There is more!

In one of my recent posts I discussed message archiving. With this post I also created a sample that can be found on MSDN Code Gallery. Recently I found out that there are some custom solutions available for message archiving:
Pipeline components are an advanced aspect of BizTalk often overlooked or often implemented in a manner that breaks the careful streaming model of BizTalk Server.  Implementing pipeline components in a truly stream based way allows BizTalk to process messages of arbitrary and effectively unlimited size.  This example shows how to use a stream to archive received messages in a way that avoids reading the entire message into memory. 
BizTalk Message Archiving - it's a pipeline component that can be used for archiving incoming/outgoing message from any adapters. It provides an option to save the message to either file (local, shared, network) or in SQL Server.
Both are excellent samples and show different aspects of message archiving and alternatives ways to do it. I believe all solutions combined can be use full for anyone has a requirement for message archiving and feels that a custom solution is the best fit.
Cheers.

Thursday, March 22, 2012

WhitePaper on Microsoft Integration Architecture: Now and the Future

Recently fellow BizTalk MVP Gijs in ‘t Veld asked me to review his whitepaper “Guidance for integration architecture on the Microsoft Business Platform”, which is now available.
Guidance
I definitely recommend every BizTalk professional to read this and/or let his or her manager read it. The paper gives the reader the most up-to-date facts on the availability and roadmap of Microsoft integration products and it provides you with high level guidance on how to design future proof integration solutions with Microsoft technology, including BizTalk Server and Azure Service Bus.
In my view it tells the story on where integration with Microsoft technology is heading and will provide you with a clear view where to invest in now as a BizTalk professional and in the future. For your manager, management and/or client you can now provide a clear story on where Microsoft integration platform is heading. Finally architects will have the ability to create a future proof architecture with guidance provided in this whitepaper.

Thanks Gijs for letting me have the opportunity to review this excellent, well written whitepaper.
Cheers!

Monday, March 19, 2012

BizTalk Community series: Introducing Jean-Paul Smit

The stories continue with the BizTalk Community Series that bring BizTalk community members to the foreground. The eight story will be on Jean-Paul Smit. He created one of the productivity enhancing tools for BizTalk solutions; the BizTalk Software Factory. He is also like me an active member of the Dutch BizTalk User Group. I had a little chat with him a while ago and this is his story. 

Jean-Paul Smit lives with his girlfriend and 2 sons of 8 and 10 years old in Hoofddorp, The Netherlands. Since 1997 he has worked with Microsoft products and from 2004 with BizTalk Server. In 2008 he started his own consultancy company to help customers with their integration issues. At the moment he works as a solution architect on the application integration team of a government agency in the Netherlands. Jean-Paul is a BizTalk MCTS and SOA Certified Professional.

Jean-Paul has a broad expertise, yet his focus is on architecture and development in the application integration and cloud area. He has worked in both the developer and architect role on small and large projects. To support the community he started the BizTalk Software Factory project on Codeplex a few years ago. With that tool you can start developing guided and consistent BizTalk solutions, so Jean-Paul is quite familiar with Visual Studio extensions. 

Jean-Paul is very curious about the direction that BizTalk is going in the near future. There is a lot of activity in the Azure area with the Service Bus EAI/EDI initiative. BizTalk is a very traditional platform and he wonders when and if customers will move towards Azure for their integration activities. On the other hand he knows BizTalk is a traditional platform, so it will be around on-premise for several years.
A part of Jean-Paul’s spare time is reserved for studying, researching new technology, writing blog posts and articles. At the moment he is working on an article about the Azure Service Bus EAI/EDI (which is published now) and on achieving the SOA Schools SOA Architect certification (which he has done by now, congrats). Besides that he spends as much time as possible with his kids, because they grow up so fast!

Jean-Paul likes mountain biking a lot and depending on the time available he spends between 2 and 8 hours a week on a bike. In 2011 he decided to spend even more time on a mountain bike and achieved 2 major goals by finishing the long distance of the Salzgammergut Trophy in Austria and the Grand Raid in Switzerland. As he states I quote: “Biking in the mountains is awesome!”
 
His message for the readers of this and other BizTalk related blogs is to keep investing time in BizTalk, also by following this and other blog sites, because he think BizTalk will be around for quite some time.
I would like to thank Jean-Paul for his story and contributions to the community.

Friday, March 09, 2012

BizTalk Messaging Archive Custom Solution

Lately one of the questions asked on BizTalk Server Forums intrigued me. The question was how one could archive a message including its message context.

Archiving received message
 
As soon as a message reaches BizTalk it can go through one of the default pipelines (XMLReceive,PassThruReceive) and a message context is added to incoming message.
                                                 Message Context
The XMLReceive pipeline has a XmlDisassembler pipeline component on the disassembling stage.

Pipeline
Whenever an Xml message is received via the XmlReceive pipeline the XmlDisassembler will do the following tasks:
  • Promote the "MessageType" context property by taking the combination of TargetNamespace and Root Element in the format of: Targetnamespace#RootElement. So one of context properties BizTalk will set (promote) is the MessageType.
Name: MessageType - Namespace: http://schemas.microsoft.com/BizTalk/2003/system-properties - http://BizTalk.Archiving.BankTransaction#Transaction
  • Remove Envelopes and disassemble the interchanges
  • Promote the content properties from interchange and individual document into message context based on the configured distinguished fields and promoted properties.
I will discuss here a custom disassembler pipeline component that will promote the “MessageType” context property and archive the message context and body to file. It will not perform the other two default actions by XmlDisassembler pipeline component.
Pipeline component is targeted for disassembler stage of the receive pipeline. The component category is CATID_DisassemblingParser will be set above the class amongst other attributes. Since the component is targeted at the disassembling stage the IDisassemblerComponent needs to be implemented. This interface has two methods, Disassemble and GetNext. In the Disassemble method you will find the implementation for archiving the received message.
        /// 
        /// Implements IDisassemblerComponent.Disassemble method.
        /// 
        /// 

Pipeline context
        /// 

Input message.
        /// Message
        /// 
        /// IComponent.Execute method is used to initiate
        /// the processing of the message in pipeline component.
        /// 
        public void Disassemble(IPipelineContext pContext, IBaseMessage pInMsg)
        {
            //Trace 
            System.Diagnostics.Debug.WriteLine("1.  Pipeline Disassemble Stage");

            //Create XmlDocument object
            XmlDocument xmlDoc = new XmlDocument();

            //Create a copy of the message
            IBaseMessage archiveMessage = pInMsg;

            //Trace
            System.Diagnostics.Debug.WriteLine("2.  Call GetMessagePayLoad()");

            //Get Message PayLoad
            xmlDoc = GetMessagePayLoad(archiveMessage);

            //Trace
            System.Diagnostics.Debug.WriteLine("3.  Message PayLoad :" + xmlDoc.OuterXml);

            // Promote MessageType in order to the Biztalk to have a unique key for evaluating the subscription
            archiveMessage.Context.Promote("MessageType", "http://schemas.microsoft.com/BizTalk/2003/system-properties", xmlDoc.DocumentElement.NamespaceURI + "#" + xmlDoc.DocumentElement.LocalName.ToString());

            //Debug 
            System.Diagnostics.Trace.WriteLine("4. Call ReadContextProperties");

            //Get the context properties and assign them to contextProperties  archiveMessage
            string contextProperties = ReadContextProperties(archiveMessage);

            //Debug 
            System.Diagnostics.Trace.WriteLine("5. Context Properties: " + contextProperties);

            //Get the message content (BodyPart)
            string messageBody = xmlDoc.OuterXml;

            //Debug 
            System.Diagnostics.Trace.WriteLine("6. Message Body: " + messageBody);

            //Debug 
            System.Diagnostics.Trace.WriteLine("7. Write to output file");

            //Write output
            using (StreamWriter outfile = new StreamWriter(_ArchiveLocation + System.Guid.NewGuid().ToString() + "_Message" + ".txt"))
            {

                //Debug 
                System.Diagnostics.Trace.WriteLine("8. File Location :" + _ArchiveLocation);

                outfile.Write(contextProperties + " " + Environment.NewLine + messageBody);

                //Debug 
                System.Diagnostics.Trace.WriteLine("9. Write to output file");
            }

            //Debug 
            System.Diagnostics.Trace.WriteLine("10. Pipeline Disassemble Stage Exit");


            //Return orginal message
            IBaseMessage outMessage;
            outMessage = pContext.GetMessageFactory().CreateMessage();
            outMessage.AddPart("Body", pContext.GetMessageFactory().CreateMessagePart(), true);
            IBaseMessagePart bodyPart = pInMsg.BodyPart;
            Stream originalStream = bodyPart.GetOriginalDataStream();
            originalStream.Position = 0;
            outMessage.BodyPart.Data = originalStream;

            outMessage.Context = PipelineUtil.CloneMessageContext(pInMsg.Context);

            _qOutMessages.Enqueue(outMessage);
            
            //Return orginal message to queue
            _qOutMessages.Enqueue(outMessage);
        }

        /// 
        /// Default method
        /// 
        /// 

Context
        /// null
        public IBaseMessage GetNext(IPipelineContext pContext)
        {
            if (_qOutMessages.Count > 0)
            {
                IBaseMessage msg = (IBaseMessage)_qOutMessages.Dequeue();
                return msg;
            }
            else
                return null;

        }

        /// 
        /// Read the context properties of the message
        /// 
        /// 

IBaseMessage archiveMessage
        /// string containing all context properties
        private string ReadContextProperties(IBaseMessage archiveMessage)
        {
            string name;
            string nmspace;
            string contextItems = "";

            for (int x = 0; x < archiveMessage.Context.CountProperties; x++)
            {
                archiveMessage.Context.ReadAt(x, out name, out nmspace);
                string value = archiveMessage.Context.Read(name, nmspace).ToString();
                contextItems += "Name: " + name + " - " + "Namespace: " + nmspace + " - " + value + "\r\n";
            }

            return contextItems;
        }

        /// 
        /// Method extract message into XMLDocument
        /// 
        /// 

IBaseMessage
        /// XML Document
        private XmlDocument GetMessagePayLoad(IBaseMessage archiveMessage)
        {
            IBaseMessagePart bodyPart = archiveMessage.BodyPart;
            Stream originalStream = bodyPart.GetOriginalDataStream();

            XmlDocument XMlDoc = new XmlDocument();
            XMlDoc.Load(originalStream);

            return XMlDoc; 
        }

The complete code can be found through MSDN Code Gallery here.

Buy versus Build

This is just a custom solution that took me a couple hours to develop and test. To add more functionality would mean more development work. A custom solution can bring a tremendous amount of flexibility and power. However it will also cost a fair amount of time to develop and some more time to maintain it (i.e. changes). An alternative can be buying one of the off-shelve products for archiving BizTalk messages like BizTalk Message Archiving Pipeline Component. This product has a great deal of features, offers support and has a license model.

BizTalk Tracking for Archiving

BizTalk offers tracking capabilities, which can be used to archive messages for a short period of time. Basically BizTalk tracking is created in such a way that you can use tracking for troubleshooting purposes not really for archiving. You can use tracking for archiving purposes, but then you need to be aware of fact that you have to configure the tracking and purging BizTalk database job correctly and move your tracking data! Why the job is so important is clearly explained in MSDN Archiving and purging the BizTalk Tracking Database:

As BizTalk Server processes more and more data on your system, the BizTalk Tracking (BizTalkDTADb) database continues to grow in size. Unchecked growth decreases system performance and may generate errors in the Tracking Data Decode Service (TDDS). In addition to general tracking data, tracked messages can also accumulate in the MessageBox database, causing poor disk performance….

By placing the backups somewhere else you can later on extract tracked messages from it. Tracked messages are compressed in BizTalk tracking database and you can extract these programmatically. Thiago Almeida has written post on how to do that. So again you need a custom solution to view the message body and its context.

You can use BizTalk tracking for archiving purposes, yet you need to offload the data from time to time to another another database. Retention on BizTalk databases is limited, because of the growth of data that eventually will impact BizTalk Server performance. In my personal opinion (view) I would not use BizTalk tracking for archiving purposes.

Archiving send message

In this post you have seen the implementation of the receive side of archiving a message. At send side a similar process can be performed to archive the message that is send by BizTalk to another system, application or service. Normally when a message is send by BizTalk, one of the default pipelines (XMLSend, PassThruSend) is used. With the XmlSend pipeline the reverse of what in a XmlReceive pipeline happens. The XMLSend has a XmlAssembler component in the Assemble stage. Whenever an Xml message is send via the XMLSend pipeline the XmlAssembler will do the following tasks:


  • XML Assembler Builds envelopes as needed and appends XML messages within the envelope.
  • Populates content properties on the message instance and envelopes. 

The custom assembler component will neither of these, it will only archive the message to file. Pipeline component is targeted for assembler stage of the send pipeline. The component category is CATID_AssemblingParser will be set above the class amongst other attributes.





[ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
[ComponentCategory(CategoryTypes.CATID_AssemblingSerializer)]
[System.Runtime.InteropServices.Guid("728609D1-8282-4D73-B4D3-4792D6580537")]

Since the component is targeted assembling stage the IAssemblerComponent needs to be implemented. This interface has two methods, Assemble and AddDocument. In the AddDocument method you will find the implementation for archiving the send message.
        /// 


        /// Implements IAssemblerComponent.Assemble method.
        /// 
        /// 

Pipeline context
        /// Message
        /// 
        /// IComponent.Assemble method is used to
        /// 
        public IBaseMessage Assemble(IPipelineContext pipelineContext)
        {
            if (_qOutMessages.Count > 0)
            {
                IBaseMessage msg = (IBaseMessage)_qOutMessages.Dequeue();
                return msg;
            }
            else
                return null;
        }

        /// 
        /// IAssembler.AddDocument Method
        /// 
        /// 

Pipeline context
        /// 

Message send out
        public void AddDocument(IPipelineContext pContext, IBaseMessage pInMsg)
        {
            //Trace 
            System.Diagnostics.Debug.WriteLine("1.  Pipeline Assemble Stage");

            //Create XmlDocument object
            XmlDocument xmlDoc = new XmlDocument();

            //Create a copy of the message
            IBaseMessage archiveMessage = pInMsg;

            //Trace
            System.Diagnostics.Debug.WriteLine("2.  Call GetMessagePayLoad()");

            //Get Message PayLoad
            xmlDoc = GetMessagePayLoad(archiveMessage);

            //Trace
            System.Diagnostics.Debug.WriteLine("3.  Message PayLoad :" + xmlDoc.OuterXml);

            //Debug 
            System.Diagnostics.Trace.WriteLine("4. Call ReadContextProperties");

            //Get the context properties and assign them to contextProperties  archiveMessage
            string contextProperties = ReadContextProperties(archiveMessage);

            //Debug 
            System.Diagnostics.Trace.WriteLine("5. Context Properties: " + contextProperties);

            //Get the message content (BodyPart)
            string messageBody = xmlDoc.OuterXml;

            //Debug 
            System.Diagnostics.Trace.WriteLine("6. Message Body: " + messageBody);

            //Debug 
            System.Diagnostics.Trace.WriteLine("7. Write to output file");

            //Write output
            using (StreamWriter outfile = new StreamWriter(_ArchiveLocation + System.Guid.NewGuid().ToString() + "_Message" + ".txt"))
            {

                //Debug 
                System.Diagnostics.Trace.WriteLine("8. File Location :" + _ArchiveLocation);

                outfile.Write(contextProperties + " " + Environment.NewLine + messageBody);

                //Debug 
                System.Diagnostics.Trace.WriteLine("9. Write to output file");
            }

            //Debug 
            System.Diagnostics.Trace.WriteLine("10. Pipeline Disassemble Stage Exit");

            //Return orginal message
            IBaseMessage outMessage;
            outMessage = pContext.GetMessageFactory().CreateMessage();
            outMessage.AddPart ("Body", pContext.GetMessageFactory().CreateMessagePart(), true);
            IBaseMessagePart bodyPart = pInMsg.BodyPart;
            Stream originalStream = bodyPart.GetOriginalDataStream();
            originalStream.Position = 0;
            outMessage.BodyPart.Data = originalStream;

            outMessage.Context = PipelineUtil.CloneMessageContext(pInMsg.Context);
            
            _qOutMessages.Enqueue(outMessage); 
        }



The complete code can be found through MSDN Code Gallery here.

Conclusion

This is a very basic and straight forward custom solution to archive messages going in and out of BizTalk Server. It can be leveraged to create a more sophisticated archiving solution. There are however some considerations that have to be taken into account.
  • When you expect a high volume of messages flowing in and out of BizTalk a lot of disk I/O will be the result when using these pipelines for archiving messages. So basically a high disk contention can occur when writing archived messages to same disk as where the BizTalk instance resides. A good approach would be having the archived messages stored on a separate dedicated disk.
  • This solution shows writing archived messages to file, yet you can also choose to store them in a database or send the archived messages to a queue where they are picked up to be stored elsewhere. In the end you have to decide where you want your archived messages stored, for how long (retention) and possibly how to retrieve them if you want to look up a certain archived message later on. The latter will be rather difficult when having archived messages on file.
  • Another thing you have to consider is data inside the messages. Is it data everyone can see or is sensitive data? Storing the files either on file or in database that easily accessible by others may not be a good option.
Having a solid, robust archiving solution in place for your BizTalk messages is an easy walk in the park. You’ll need a good design up front that is fit for purpose. I hope that with this post you have some food for thought.

Wednesday, March 07, 2012

BizTalk Community series: Introducing Ruth Resende

During the MVP Summit I had a chat with our sole female on the BizTalk MVP program, Ruth Resende. I have met her before at the MVP Summit 2011 and at this summit I got the chance to catch up with again. I interviewed her for my BizTalk Community Series that brings active BizTalk community members to the foreground. Last couple of years Ruth has done an amazing job in the Portuguese speaking BizTalk community. Below you will find a picture of us together during the MVP Summit 2012.
iPhone 240
Ruth Resende is a 30 years old women from Brazil. She lives in Cubatao (a city near Santos) and works in Sao Paulo at Itgroup Consulting since 2008. For 8 years and counting she has been in the IT arena. Ruth started as a Delphi developer before one of her friends dragged her into the Microsoft world. Once in this world Ruth soon started working with BizTalk and became very active in the Brazilian community.

How did Ruth become so active in the Brazilian BizTalk community? Well one day she was configuring the HTTP adapter a couple of times and found the English tutorial hard to understand. Her English as she states is not very good. This brought her on the idea to translate the tutorial in Portuguese. By then she also found out that there was almost no BizTalk related information available in Portuguese. So she started writing blog posts in Portuguese on different BizTalk topics. Her manager noticed her activities and asked her to work with a team that writes BizTalk related material for BizTalk Brasil (a community blog). All activities combined (including MSDN activities) resulted in her being awarded MVP by Microsoft (see her profile here). Note she was the first women ever in Brazil awarded MVP.

When Ruth works on BizTalk projects she is more on the development and administration side. During development there are some features of BizTalk she really likes. Amongst these are the Schema Flat File Wizard, and Well-Formed XML Wizard, which both in her view improve productivity. In general Ruth finds BizTalk a great Microsoft product. However I quote:

I really like work with Biztalk, but we are loosing market in Brazil. Over the years, the clients are disappearing. I hope next year Microsoft could reborn some strategy to Biztalk.”
 
Ruth likes to reads books, watch movies, animations and TV Series in her spare time. She not the sporty type, but she does like to play video games and as she states I quote: “Video games count as a sport :)” As you can see on the picture she is huge fan of the Brazilian soccer team (Canarinhos).
Ruth likes to share her experiences with BizTalk on the BizTalk Brasil blog. She states and I quote:

What I write on the blog are my on experiences, and my intention is reduce effort of someone who experienced the same problem.I hope that I can help the community, make the BizTalk better known in the world.”
 
I like to thank Ruth for her time and contributions to the community. Ruth your English is fine!