Let's take a look at a way to solve a specific problem, and see how the strategy opens the door to doing a lot of interesting things via code in BizTalk. 


BizTalk solutions frequently see the need to batch data. When you're dealing with large numbers of records (tens of thousands or more), and especially if you are dealing with large messages, doing this in memory can be risky. Sure, it might work in test. But in production, with other interfaces making demands on memory resources, it's not a safe bet. 


Better that you should aggregate to a file on disk.  Send out your individual messages to be appended to a single file, and then move that file when finished. 


Here's a neat trick to do that in a very BizTalk way. Obviously it's easy to send messages out a port with it set to append. But two little tricks make it easy to leverage this to build your aggregate on disk. 


First, you want to use a temp file name, in case one instance of your aggregation crashes so that you don't mix records from two instances. For that, we come up with a file name that is a GUID.  Declare an orchestration variable of type string to hold the name, and in an expression set it to: 

System.String.Format("(0)", System.Guid.NewGuid() )


When you construct your messages you will be aggregating, set YourMessage(FILE.ReceivedFileName) context property to this variable,  and in your send port use the %SourceFileName% macro, so your records accumulate to the name of the temp file. 


Now comes the really interesting part. You will have a receive location set to that file directory to pick up the aggregated file. But how to make sure it doesn't get picked up until the file is finished aggregating? 


By disabling and enabling that receive location in an expression object.  You will need to know the name of the receive location and receive port. You can hard code these if you're lazy, but really you should store them in the SSO as with any meta-data. 


Before you start your aggregation, call our little helper class to disable the receive location: 


MyStuff.Helpers.ReceiveLocationSwitch.Disable(PortName, LocationName)


(where of course PortName is a string variable that is the name of the receive port, and the same for LocationName)


After you are done aggregating, turn the receive on to whisk away the file to its final destination:


MyStuff.Helpers.ReceiveLocationSwitch.Enable(PortName, LocationName)


This helper class relies on WMI to query the BizTalk management database and use the methods exposed. The WMI model is a great set of tools to read and manipulate the BizTalk management database from code. 


In this case, the heart of it lies in: 


Finding the object representing the port:
String.Format("Select * from MSBTS_ReceiveLocation where ReceivePortName=\"{0}\" and Name=\"{1}\"", receivePortName, receiveLocationName)


You can see the code is really very simple. Learning your way around WMI queries and available methods opens up a rich set of possibilities. Just to take one example, you can write a C# app that reads a file contianing a list of receive locations that should always be enabled, checks their status, and if they are disabled/stopped turns them back on.  Very handy if you have network connectivity issues that brings down your receive locations.  


Want to restart your hosts once a week? Or insure they are always running? The WMI api is a way to do this from, well, anything: C#, Powershell, even a stored procedure if you wanted to. 


So that's our nifty way of aggregating files to disk, but also an addition to our toolkit to do all kinds of things with BizTalk from code that you think of as manual/admin activities. Use your imagination, and let us know what kinds of creative uses you come up with! 


Here's our helper class: 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Management;
using System.Xml;
 
 
 
 
namespace MyStuff.Helpers
{
    [Serializable]
    public class ReceiveLocationSwitch
    {
         
 
 
        public void Enable(string receivePortName, string receiveLocationName)
        {
             
            Execute(receivePortName, receiveLocationName, true);
        }
 
 
        public void Disable(string receivePortName, string receiveLocationName)
        {
            Execute(receivePortName, receiveLocationName, false);
        }
 
 
 
 
        private void Execute(string receivePortName, string receiveLocationName, bool Enable)
        {
 
 
 
            string WMIQuery = String.Format("Select * from MSBTS_ReceiveLocation where ReceivePortName=\"{0}\" and Name=\"{1}\"", receivePortName, receiveLocationName);
 
 
            EnumerationOptions enumOptions = new EnumerationOptions();
 
 
            enumOptions.ReturnImmediately = false;
 
 
 
 
            ManagementObjectSearcher RcvSearcher = new ManagementObjectSearcher("root\\MicrosoftBizTalkServer", WMIQuery, enumOptions);
 
 
 
            // the collection will have only one member so this foreach will be quick
            foreach (ManagementObject RcvInstance in RcvSearcher.Get())
 
 
            {
 
 
                 
                // Boom!
                RcvInstance.InvokeMethod((Enable)?"Enable":"Disable", new object[] { 2, 2 });
 
 
            }
 
 
        }
 
 
    }
}