Welcome to MSDN Blogs Sign in | Join | Help

More Information on Processing MSMQ Messages in FIFO Order

In two of my previous posts  I talked about processing MSMQ messages in FIFO order with WCF.

The way that WCF, along with the MSMQ binding, works there could be a couple of situations in which messages may actually not process in FIFO order. 

The most prevalent is a rollback.  When a message is rolled back the process is asynchronous and thus end up not only having that message take time to get back to the head of the queue but may also lead to messages being processed while the rolled back message is in flight. 

However, not all is lost.  By adding the changes below you can further ensure that you can make WCF behave like a pure System.Messaging coded system and still get your messages in FIFO order.

So, add

<transactedBatching maxBatchSize="1"/>

as an endpoint behavior and setting

ReleaseServiceInstanceOnTransactionComplete = false

on the Service Behavior (along with the InstanceContextMode and the ConcurrencyMode)

Posted by skaufman | 1 Comments
Filed under: , ,

More Information on UpdateGrams

In previous blog posts I have mentioned this large project that I am working on.  This project has been a great project for finding lots of material to blog about.  What I have not mentioned so far are the people that I am working with. 

This project is a joint effort between Microsoft Consulting Services and Microsoft Global Services India (MGSI).  There have been great contributions by all of the off-shore team (unfortunately, far to many to list) and I would recommend them anytime as an off-shore group if you are looking to implement an off-shore model. 

I have been very fortunate to be working closely with a small tight knit sub team.  This team is made of up Vishal Agrawal, Ashish Mehndi, Ashish Shukla and Benny Matthew.

Why do I bring this up?  Well, in the last blog post I talked about changing the config file so that we could validate our canonical messages.  Once we did that we quickly found out that all of our interchanges that utilized a SQL UpdateGram broke.  They broke because the map that generates the UpdateGram uses a character to represent the parent/child relationship.  This character gets mapped to an element that is an Integer type - which is were it no longer conforms to the schema.  We did this because when the UpdateGram was sent through the Send Port the SQL Adapter uses SQLXML which takes that character data and replaces it with the value of the parents primary key.

So, the first thing that we did was to modify the map to use a numeric value (yes, numeric values can be used) and we decided that we were going to use the following scheme so that we would not overlap with real data.   We used a script functoid with the following code

System.Int32.MinValue.ToString() + the value from the iteration functoid.

Why do I bring up the issue with overlapping data?  Well, that brings us to the second interesting (and important) fact about using the UpdateGram. 

How does the SQLXml functionality work internally when replacing the child key with the value from the parent?  Well, it takes the identifier (lets say that we were still using a character and that the character was Y) and does a string replace.  The string replace however is done across all of the data in the child record and not just the child foreign key column.  We found very quickly that all of our columns that contained a Y were now replaced with the value from the parent key relationship - definitely not what we wanted!  This only happens if the data in the field is only a Y.  This does not happen if there is a Y in the middle of a word.

So, if you are still going to use character data to identify your relationships in the UpdateGram make sure that you take this into account.

Posted by skaufman | 1 Comments
Filed under:

Validating Schemas During Runtime

I recently came across an interesting scenario.  In my application, we are transforming multiple incoming messages to a a canonical format.  We then take the output and place it in the MessageBox for some other downstream subscriber to process. 

The Mapper did the transformation and created the output, however, based on the processing that we were doing during the mapping we found that some of the output messages we created did not always get created so that they would pass validation against the canonical schema.  Since we were doing our processing without the use of an Orchestration we did not have the ability to call a pipeline component to do the validation.   In addition, since the canonical message was used as input to the next set of processes we couldn't use a pipeline on the send side either.

What we needed was the ability to validate against the output schema without requiring an Orchestration.

By adding the following items to the BizTalk config file on all of our servers we were able to achieve this behavior.

 <configSections>
    <section
        name="xlangs"
        type="Microsoft.XLANGs.BizTalk.CrossProcess.XmlSerializationConfigurationSectionHandler, Microsoft.XLANGs.BizTalk.CrossProcess" />
</configSections>

<xlangs>
    <Configuration>
        <Debugging
            ValidateSchemas="true"
            ExtendedLogging="false"
        />
    </Configuration>
</xlangs>

Once you make this change make sure that you test all of the messages that you are processing in your environment.  There is a good chance that you could end up generating suspended messages for interchanges that were just working.

An prime example is if you are using SQL UpdateGrams as outlined in this previous post.

In my next post I will talk about how to get around this issue and another very curious and frustrating UpdateGram behavior.

Posted by skaufman | 1 Comments
Filed under:

Software Development Meme

Well, it would appear that I have been 'tagged' to answer a few question on how I got started in this business.  This chain seems to have started back quite a ways and it is interesting to see how many degrees of separation there really are between people - I always knew that this was a small community. 

Anyways, Scott Colestock, called me out to be next on the chain (along with a couple of other people) so here goes.

First, I didn't know what a Meme was.  So, I went to the dictionary and this is what it has to say.  A Meme is "A unit of cultural information, such as a cultural practice or idea, that is transmitted verbally or by repeated action from one mind to another."

Second, I have been blogging for over 4 years and I have never put anything of a personal nature in any of my posts.  So, this may be more than you ever wanted to know so read on at your own risk :-)

How old were you when you started programming?

I was in 8th grade.  My best friends father purchased an Apple II that he was going to use for his business along with VisiCalc.  The computer was placed on a card table in the middle of their basement.  It was like it was a show piece but no one really knew what to do with it.  My friend and I spent nearly all of our free time playing with the computer and learning VisiCalc and creating calculations for his fathers business.  We quickly got tired of VisiCalc and needed something else to keep us interested.  We started programming and entering commands to see what the machine would do.  We quickly got tired of seeing Syntax Error and decided it was time to get a bit more serious.

What was your first language?

Basic

What was the first real program you wrote?

My friend and I decided to write a maze game.  The graphics (if you can really call them that) were big white blocks that we placed on the screen.  I think it was really too big to take on as our first application since it took us a really long time.  It was a good learning experience in regards to how long things take - a good lesson for the future.

What languages have you used since you started programming?

Well, it started out with Basic, then QuickBasic.  Then I did three years of COBOL programming on a VAX (but I have never told anyone that and I would like to keep it that way).  I did a lot of statistics programming in a proprietary language as well as a lot of DBASE III+.  Then I got into PowerBuilder v2.0 and something new called Visual Basic 1.0.   I have programmed (and put software into production) with every version of Visual Basic from 1.0 to 6.0.  I even received my first Microsoft certification on VB3.  There were other languages that I played around with but never did anything with them professionally.  Anyways, when .NET was released I jettisoned all previous development languages and have focused on C# for the last 7 years.  This question only talks about languages but I would be remiss if I didn't put BizTalk somewhere in this post.

What was your first professional programming gig?

Officially my first professional programming gig was when I graduated college and worked for a marketing research company.

If you knew then what you know now, would you have started programming?

Absolutely.  Looking back at where things have come it is incredible the amount of new things to learn and be a part of.  I love the fact that there is always a new challenge and there has never been a boring day.  There certainly have been days where I felt like ripping my hair out though or banging my head on a softer part of the wall.

If there is one thing you learned along the way that you would tell new developers, what would it be?

Always keep the architecture in mind.  It is very easy to focus only on the specific low level technology.  Also, never forget that development is only 30% of the effort of a project.  You can have a lot of fun with performance tuning and throughput analysis - ok, a bit geeky but still, you can have fun with it.  Also, surround yourself with Type-A, hard working, curious, energetic people.

What's the most fun you've ever had...programming?

hmm...I have had fun working with small teams where we get a lot accomplished in a very short amount of time.  However, I find that I get my greatest sense of accomplishment from working on troubled projects/death march projects and turning them around and getting them finished. 

The worst/best was a year long project for the Texas Prison System.  Imagine working for 72 hours straight with two other team members trying to meet a contract deadline and the work was done on the prison grounds.  We met the timeframe and drank an incredible amount of Mt. Dew along the way (I am not sure which I am more proud of).   

We learned a lot about the prison system, escape stories and a renewed understanding why scared straight programs work so well.  All of which I would be happy to tell you over beers.

Who am I calling out?

Andy Morrison

 

Posted by skaufman | 1 Comments

I will be speaking at TechEd 2008

TechEd Banner

I will be presenting at TechEd 2008.  This will be my fourth time presenting at TechEd conferences.  This time I will be co-presenting with Todd Van Nurden and we are speaking on automated testing and deployment for BizTalk.  We are giving this presentation at the IT Professional week of TechEd and so our presentation won't be completely geared towards development but one of the things we will be showing is how to deploy BizTalk using PowerShell. 

If you are going to be there stop by and say hello.

Here is the official Info:

SOA59-TLC Automated Testing and Deployment for BizTalk
Session Day/Time: 6/10/2008 3:00PM-4:15PM

Posted by skaufman | 0 Comments
Filed under: ,

System Center Operations Manager and BizTalk

The SCOM 2007 BizTalk Management Pack has finally been released.  The Management Pack is a complete rewrite and covers BizTalk 2006, BizTalk R2 as well as the new features of R2 including RFID and the EDI functionality. You can download the Management Pack here.

 

Also, If you were familiar with the Management Pack for MOM 2005 you will notice a number of changes.  The biggest is the change to the alerting functionality.  In SCOM you create subscriptions which will provide you with alerts for all of the events.  If you are looking for the alerting functionality that MOM 2005 had (the ability to pick a rule and provide an alert based only on that rule) you can find a Powershell script on the Manageability Team Blog titled: OpsMgr 2007: Creating a subscription for future occurrences of an alert. The script takes two parameters; the RMS server address and e-mail address you want notifications sent to.  After you follow the steps outlined you will see a specific notification for that problem and SCOM will send e-mails to the e-mail address you entered in the script.

 

Posted by skaufman | 1 Comments
Filed under:

I will be speaking at the Omaha BizTalk User Group

I will be speaking at the Omaha BizTalk User Group April 3rd 2008 on Team Development and Testing.  This is taking place at the Microsoft offices.

If you are going to be around stop by and say hi.

Posted by skaufman | 0 Comments
Filed under: ,

Matching the BizTalk Service Name with its PID

I have been working with pipeline components quite a bit recently and when I try to attach to the BizTalk Server process I find that there are a lot of host instances and I need to determine which one to attach to.

If you run the tasklist utility from a command prompt it will enable you to get a list of the host instances (services) as well as the name and PID.  Exactly what we need to determine what to attach to.

If you have a 32 bit hosts then run the following:

tasklist /SVC /fi "imagename eq btsntsvc.exe"

and if you have 64 bit hosts then run this:

tasklist /SVC /fi "imagename eq btsntsvc64.exe"

the /fi is a filter and the eq is equals. 

The results that will come back will look something like

Image Name                        PID    Services
================== ==== ===============================
BTSNTSvc.exe                   6324    BTSSvc$BizTalkServerApplication
BTSNTSvc.exe                   3676    BTSSvc$BizTalkServerReceive
BTSNTSvc.exe                   6152    BTSSvc$BizTalkServerSend

Posted by skaufman | 1 Comments
Filed under: ,

Removing XML elements from an input document (with large message support)

In my last post I talked about taking an XML message and stripping out elements.  In that post I used a standard MemoryStream object and a reader requested that I also talk about how this pipeline could be created to deal with streaming of large messages.  Lets take a look at what those modifications would look like.

 

When dealing with large incoming messages you don't always want to load the message into memory - which is typically what the MemoryStream object does.  BizTalk has included a set of objects in the Microsoft.BizTalk.Stream.dll (located in the GAC) that provide a means of handling large messages.  Within this assembly is the VirtualStream class (the source code can be found in the SDK under the \Program Files\Microsoft BizTalk Server 2006\SDK\Samples\Pipelines\ArbitraryXPathPropertyHandler directory in the VirtualStream.cs file).  This objects behavior provides the means to keep the stream data in memory up to 4MB (this is the default threshold) and once that threshold is reached the additional data is written to a temporary file on the hard drive.

 

If you decide that this functionality is what you are looking for then you need to keep a couple of things in mind.  Since the BizTalk service will be writing a file to the hard drive you need to make sure that the BizTalk account has the security privileges to write to the %temp% folder (this will be the %temp% folder on each of the BizTalk servers for each of the host instances).  Also, by default, the %temp% folder is placed on the C:\ drive.  You need to decide if that is where you want the temp file to be created.  You most likely will want to configure your server to put it on a different drive since the C:\ is typically configured with a small amount of storage space.  You will also want to make sure that the location of the new %temp% directory is not getting backed up.   

 

So, the first thing is that we need is to set a reference to the Microsoft.BizTalk.Streaming.dll.  This is located in the GAC and therefore you will not be able to add the reference within Visual Studio to this location.  You will need to copy the .dll from the GAC and place a copy of it somewhere else on your hard drive and add the reference to that copy.  You can do this through a command prompt and navigate to its location (on my machine it was C:\WINDOWS\assembly\GAC_MSIL\Microsoft.BizTalk.Streaming\3.0.1.0__.......). 

 

Instead of using a MemoryStream we will use the VirtualStream object.  When we new up our object we are presented with 6 overloads.  We want to use the overload that allows us to pass in the VirtualStream.MemoryFlag.  The options of this enum are OnlyToDisk, OnlyInMemory and AutoOverFlowToDisk.  We want to use the AutoOverFlowToDisk.  If you want to change the memory threshold then use the following overload; VirtualSream(int bufferSize, VirtualStream.MemoryFlag).

 

So, the Execute method now looks like this:

 

        public …... Execute(……….)

        {

            try

            {

                IBaseMessagePart bodyPart = inmsg.BodyPart;

                VirtualStream vs = new VirtualStream(VirtualStream.MemoryFlag.AutoOverFlowToDisk);

 

                if (bodyPart != null)

                {

                    Stream originalStream = bodyPart.GetOriginalDataStream();

 

                    if (originalStream != null)

                    {

                        XmlTextReader Xtr = new XmlTextReader(originalStream);

 

                        XmlTextWriter Xtw = new XmlTextWriter(vs, Encoding.UTF8);

   …..

   …..

   …..

 

             }

               

                vs.Position = 0;

                bodyPart.Data = vs;

                pc.ResourceTracker.AddResource(vs);

                return inmsg;

            }

 

The items in bold outline the lines that changed when we used the VirtualStream object.

Posted by skaufman | 1 Comments
Filed under:

Removing XML elements from an input document

 

I am working on a BizTalk application where we are processing messages from a Point of Sale (POS) system.   As it turns out these messages contain a lot of data that we don't need such as receipt data in HTML format embedded in an element and a number of other elements which contain data specific to the POS system.  This extra data made the size of these messages overly bloated and we didn’t want to incur the performance overhead of dealing with the bloat.  The thing to do in this situation was to strip the unneeded data before processing it.

 

So, the first thing, of course, was to check if something like this has already been done and if anyone had blogged about it.  Nothing.  So, on the plane home the XMLStripper pipeline component was started.

 

The first decision was that this was going to be done as a pipeline component - that was a pretty simple decision.  Next, it had to process the xml in a streaming fashion since I knew that the messages were going to be large and I didn't want to take the memory hit on loading it into the DOM.  I also wanted the processing to continue even if the stripping functionality couldn't take place (which meant we still needed the removed elements to be in the schema).  Lastly, it needed to take a list of elements to exclude and it needed to pass through any node type it encountered.

 

Since I needed to get a list of elements to remove I utilized the property bag functionality with the Load and Save (shown below) methods to allow this list to be passed to the pipeline from the properties page in Visual Studio.

 

        public virtual void Save(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, bool fClearDirty, bool fSaveAllProperties)

        {

            this.WritePropertyBag(pb, "RemoveElements", this.RemoveElements );

        }

 

Next was the Execute method.  In this method I used the XmlTextReader to get the streaming functionality that I needed.  I also used a List object to hold the elements that needed to be stripped from the XML message.  The real work happens in the while block where I inspect each node.  If the node is an element (specifically not an EndElement) then I check if the name is contained in the List object.  If it is then I flip a flag  (encounteredRemovedTag )  which is utilized in the NodeType.Text switch and the NodeType.EndElement switch blocks.  This flag is important because if a node is encountered that needs to be stripped then all embedded nodes also have to be stripped.

 

In the NodeType.EndElement switch block I check if the name of the end node is equal to the value stored in currentElementToBeRemoved.  If so, then I know that we need to flip the flag (encounteredRemovedTag) and continue processing each node normally.

 

Each of the rest of the switch blocks process all other NodeTypes encountered and continue to build the output xml message.  At the very end of the process I take the new XML message, which is now contained in the MemoryStream, set its position back to 0 and pass that to the IPipelineContext ResourceTracker.

 

The code for the Execute method (only the relevant code) of the pipeline component looks like this:

 

 

        public …... Execute(……….)

        {

            try

            {

                IBaseMessagePart bodyPart = inmsg.BodyPart;

                MemoryStream ms = new MemoryStream();

 

                if (bodyPart != null)

                {

                    Stream originalStream = bodyPart.GetOriginalDataStream();

 

                    if (originalStream != null)

                    {

                        XmlTextReader Xtr = new XmlTextReader(originalStream);

 

                        XmlTextWriter Xtw = new XmlTextWriter(ms, Encoding.UTF8);

                        Xtw.Formatting = Formatting.Indented;

 

                        List<string> RemoveElementsList = new List<string>();

 

                        RemoveElementsList.AddRange(RemoveElements.Split(','));

 

                        Xtr.WhitespaceHandling = WhitespaceHandling.None;

 

                        bool continueProcessing = true;

                        bool encounteredRemovedTag = false;

                        string currentElementToBeRemoved = string.Empty;

 

                        if (Xtr.Read() == false) continueProcessing = false;

 

                        while (continueProcessing)

                        {

                            switch (Xtr.NodeType)

                            {

                                case XmlNodeType.Element:

                                    if (RemoveElementsList.Contains(Xtr.Name))

                                    {

                                        currentElementToBeRemoved = Xtr.Name;

                                    }

 

                                    if (Xtr.Name != currentElementToBeRemoved && !encounteredRemovedTag)

                                    {

                                        Xtw.WriteStartElement(Xtr.Prefix, Xtr.LocalName, Xtr.NamespaceURI);

                                        Xtw.WriteAttributes(Xtr, true);

                                    }

                                    if (Xtr.Name == currentElementToBeRemoved) encounteredRemovedTag = true;

                                    if (Xtr.IsEmptyElement && !encounteredRemovedTag)

                                    {

                                        Xtw.WriteEndElement();

                                    }

                                    break;

                                case XmlNodeType.EndElement:

                                    if (!encounteredRemovedTag)

                                    {

                                        Xtw.WriteFullEndElement();

                                    }

                                    if (Xtr.Name == currentElementToBeRemoved)

                                    {

                                        encounteredRemovedTag = false;

                                        currentElementToBeRemoved = string.Empty;

                                    }

                                    break;

                                case XmlNodeType.Text:

                                    if (!encounteredRemovedTag)

                                    {

                                        Xtw.WriteString(Xtr.Value);

                                    }

                                    break;

                                case XmlNodeType.Whitespace:

                                case XmlNodeType.SignificantWhitespace:

                                    Xtw.WriteWhitespace(Xtr.Value);

                                    break;

                                case XmlNodeType.CDATA:

                                    Xtw.WriteCData(Xtr.Value);

                                    break;

                                case XmlNodeType.EntityReference:

                                    Xtw.WriteEntityRef(Xtr.Name);

                                    break;

                                case XmlNodeType.XmlDeclaration:

                                case XmlNodeType.ProcessingInstruction:

                                    Xtw.WriteProcessingInstruction(Xtr.Name, Xtr.Value);

                                    break;

                                case XmlNodeType.DocumentType:

                                    Xtw.WriteDocType(Xtr.Name, Xtr.GetAttribute("PUBLIC"), Xtr.GetAttribute("SYSTEM"), Xtr.Value);

                                    break;

                                case XmlNodeType.Comment:

                                    Xtw.WriteComment(Xtr.Value);

                                    break;

                            }

                            continueProcessing = Xtr.Read();

                        }

 

                        Xtw.Flush();

                    }

                }

               

                ms.Position = 0;

                bodyPart.Data = ms;

 

                pc.ResourceTracker.AddResource(ms);

                return inmsg;

            }

 

 

Posted by skaufman | 2 Comments
Filed under: ,

Processing multiple queues in FIFO order with WCF

In my previous entry on Processing FIFO MSMQ Messages using WCF I said that I would cover processing multiple queues and processing each queue in FIFO order. 

 

If you remember, our requirement was to processe messages we receive from a legacy system through MSMQ in FIFO order.  Well we found that there were a couple of issues.  Neither of them was a surprise - FIFO processing is slow and there is no scale out.   

 

So, we did a little more investigation and we found that we could segment our processing by message types (each being sent through their own queue) and then process each in FIFO order.  The FIFO processing is the same as in the past blog post.  This blog entry is focused on dynamically adding and creating hosts for each of the queues.

 

We need a way to be able to add queue bindings in the .config file and have the application recognize the new queue without the need to modify code or have the application have any knowledge of how many queues would be monitored.

 

So, with this, I would set up the .config file looks like this:

 

<services>

<service name="EventManagement.MSMQEventServiceTypeX" >

<endpoint address="msmq.formatname:DIRECT=OS:.\private$\EventManagementQueueX"

  binding="msmqIntegrationBinding"

  bindingConfiguration="EventProcessorBinding"

  behaviorConfiguration="BatchingBehavior"

  contract="EventManagement.IMSMQEventInterface">

</endpoint>

</service>        

<service name="EventManagement.MSMQEventServiceTypeY" >

<endpoint address="msmq.formatname:DIRECT=OS:.\private$\EventManagementQueueY"

  binding="msmqIntegrationBinding"

  bindingConfiguration="EventProcessorBinding"

  behaviorConfiguration="BatchingBehavior"

  contract="EventManagement.IMSMQEventInterface">

</endpoint>

</service>

</services>

 

The idea is to be able to add a new service entry for each new message type with a new endpoint address and have the code spin up a new service host.  The code to make this happens looks like this:

 

 

public class EventProcessor

    {

        private List<ServiceHost> svcHosts = new List<ServiceHost>();

        private MSMQEventService mqevtsvc;

 

        public void ProcessMessages()

        {

            mqevtsvc = new MSMQEventService();

 

            ServicesSection SvcSec = (ServicesSection)ConfigurationManager.GetSection("system.serviceModel/services");

 

            string MSMQSvcName = mqevtsvc.GetType().FullName;

 

            string baseName = ConfigurationManager.AppSettings["EventQueueName"];

            Uri baseAddress = new Uri(baseName);

 

            //Roll through the service entries and create service hosts to handle them

            foreach (ServiceElement svc in SvcSec.Services)

            {

                if (svc.Name.StartsWith(MSMQSvcName))

                {

                    object svcObj = null;

                    string Suffix = svc.Name.Substring(MSMQSvcName.Length);

 

                    if (Suffix == string.Empty)

                    {

                        svcObj = mqevtsvc;

                    }

                    else

                    {

                        svcObj = CreateMSMQObj(Suffix);

                    }

 

                    if (svcObj == null)

                    {

                        ErrorHandler.Instance.OnError("Error creating service type " + mqevtsvc.GetType().Name + Suffix, EventLogEntryType.Warning, ErrorHandler.WarningNumber.ServiceStarting);

                    }

                    else

                    {

                        ServiceHost newSvc = new ServiceHost(svcObj, baseAddress);

                        newSvc.Faulted += new EventHandler(serviceHost_Faulted);

 

                        svcHosts.Add(newSvc);

                    }

                }

                else

                {

                    ErrorHandler.Instance.OnError(string.Format("Service name {0} must begin with {1}", svc.Name, MSMQSvcName), EventLogEntryType.Warning, ErrorHandler.WarningNumber.ServiceStarting);

                }

            }

 

            // Open the ServiceHostBase to create listeners and start listening for messages.

            foreach (ServiceHost svcHost in svcHosts)

            {

                svcHost.Open();

            }

        }

 

        private object CreateMSMQObj(string SuffixName)

        {

            CSharpCodeProvider loCompiler = new CSharpCodeProvider();

 

            CompilerParameters loParameters = new CompilerParameters();

 

            loParameters.ReferencedAssemblies.Add("System.dll");

 

            loParameters.ReferencedAssemblies.Add(this.GetType().Assembly.Location);

            loParameters.ReferencedAssemblies.Add(typeof(ServiceHost).Assembly.Location);

 

            loParameters.GenerateInMemory = true;

 

            string Code = @"

using System;

using System.ServiceModel;

namespace EventManagement

{

    public class MSMQEventService{0} : MSMQEventService, IMSMQEventInterface, IDisposable

    {

    }

}

";

            Code = Code.Replace("{0}", SuffixName);

 

            CompilerResults loCompiled = loCompiler.CompileAssemblyFromSource(loParameters, Code);

 

            if (loCompiled.Errors.HasErrors)

            {

//……add code here to process errors            

            }

 

            Assembly loAssembly = loCompiled.CompiledAssembly;

 

            object loObject = loAssembly.CreateInstance("EventManagement.MSMQEventService" + SuffixName);

 

            return loObject;

        }

}

 

There are two interesting parts to this code.  The first is at the top where the .config file is read.  The second is in the CreateMSMQObj private method. 

 

When the .config file is read the service name attribute is read and that is used as part of the class name that is used with the ServiceHost.

 

During the CreateMSMQObj method, we are dynamically creating a class for each of the service elements from the .config file. 

 

At this point we have a system that can dynamically read from multiple queues, defined at runtime, and process the messages in each queue in FIFO order.

 

This code is not the full source code and some of the processing code has been taken out for brevity.  Hopefully, this will provide a glimpse and a provide a head start to process multiple queues in FIFO order.

Posted by skaufman | 1 Comments
Filed under: , ,

MSMQ Label Property and WCF

The label property of an MSMQ message has been used for many things.  Developers still use the label property and want to continue to use it.  So, how do you get access to this property in WCF before posting your message to the queue. 

It turns out that if you are using the NetMSMQBinding you can't.  After thinking about this a bit it makes sense since the NetMSMQBinding only uses MSMQ as an transport mechanism between two endpoints.  In this case any data you want to send between these two endpoints needs to be in the message body.  This is so your endpoints can be agnostic to the underlying transport and allow you to swap it out without having to modify your code.

To be able to utilize the label property you need to use the MsmqIntegrationBinding.  The MsmqIntegrationBinding class enables WCF to use the types defined in the System.Messaging namespace.  The label property is on the MsmqIntegrationMessageProperty class which can be used as follows:

MsmqIntegrationMessageProperty property = MsmqIntegrationMessageProperty.Get(message);

string lbl = property.Label

Posted by skaufman | 1 Comments
Filed under: , ,

Finding the latest written document in a directory

I am working on a BizTalk test system within TFS for a client.  They are sending the output messages to a file location and using a GUID as the file name.  They have a requirement to take the output message and compare it to a known good output to determine if they are the same or not. 

 

Since we don't know the name of the file we needed something to use to find the file.  Unfortunately, we did have anything in the file itself to correlate on nor could we add anything.  So, we decided that we would take the last written file in the output directory.  I thought there must be some code snippet that someone has already created to do this and to my surprise I couldn't find one.  Now there is.

 

I grab the files in the directory and add them to a SortedList with the DateTime as the key and the full path and file name as the value.  I then take the one at the top of the list and use that.  The code is below:

 

XmlDocument outputDocument = new XmlDocument();

string outputDocumentFilePath;           

DirectoryInfo dir = new DirectoryInfo(outputLocation);

            SortedList sl = new SortedList();

                foreach (FileInfo fi in dir.GetFiles())

                {

                    String fname = fi.Name;

                    DateTime dt = fi.LastWriteTime;

                    sl.Add(dt,fi.DirectoryName + @"\" + fname);

                }

               

            //Read the output document from the Orchestration found in the output directory

            outputDocumentFilePath = sl.GetByIndex(sl.Count -1).ToString();

                   

            outputDocument.Load(outputDocumentFilePath);

 

There are a couple of potential issues.  What happens if more than one person is testing and multiple people are looking for their output file? What happens if BizTalk takes longer to process the message and you read the latest file before BizTalk writes out the file?

 

These are outside the scope of this entry - remember, this was just going to be how to grab the last written file in a directory of output files.

Posted by skaufman | 1 Comments
Filed under: ,

BizTalk Mapping Design Template

I visit a lot of customers and I hear many of the same questions.  One of the most common at the beginning of a project is how do I document and design the transformations.

 

I have created a template (that you can download) that I use and provide when I am on a project to the architects, developers and business analysts.  I find that the business analysts are typically in the best position to do this part of the analysis and they are most often very comfortable with an Excel spreadsheet.

 

Each map will have an associated Excel spreadsheet.  Within the spreadsheet are 4 tabs.  The first contains history information such as the author, date, version and description.  The second and third tab are the mappings for a request and response message scenario.  If this map represents a one way message then delete one of the tabs.  On these mapping tabs I have included the source schema information in column B, destination schema information in column J (there is other data on the form pertaining to the schemas) and the transform information in column G.  Column G maps to the fourth  tab which represents the transformation functions. 

 

In the template, I have included a sample of a public schema mapped to a canonical schema as well as a sample response message mapping.  On each of the tabs I have included examples of the types of mapping that you will encounter including:

Mapping from source to destination

Creating a destination value  with no mapping from the source

Mapping source to destination through the use of a functoid

Mapping a source element to two destination elements

 

Posted by skaufman | 1 Comments
Filed under:

I will be speaking at TechEd EMEA's IT Forum

http://www.microsoft.com/europe/teched/

I am very excited that I will be presenting at TechEd EMEA this year. I am presenting on Monitoring BizTalk Server SOA solutions with MOM. 

If you are going to be there stop by and say hello.

My session is:

WSI301 Creating and Managing SOA Solutions with BizTalk Server and Microsoft Operations Manager

Posted by skaufman | 1 Comments
Filed under: