Scenario

This is a common scenario: XML Files are received from a file location, transformed by a map to a flat file schema , flattened by a flat file assembler pipeline component and sent to another file location. 

It is also common for the files to have meaningful names and the flattened file need to have the same name, but with a different extension. So if Orders_0001_20110121.xml comes in, Orders_0001_20110121.txt has to come out, for example. 

Solution

Flattening the file

While it is not the scope of this article to explain how to flatten a file, I will mention that a Flat File Schema has to be created, and I do that using the Flat File Schema Creation Wizard. Also, a custom pipeline has to be created and the Flat File Assembler pipeline component has to be added to it. For the purpose of this article I have a created a Send pipeline and dropped the Flat File Assembler in the Assemble stage of the pipeline. 

Naming the target file using the source name with a different extension

To achieve that we will modify the content of the ReceivedFileName promoted property using a custom pipeline component, and will retrieve this promoted property on the send port using the %SourceFileName% macro.

Implementation

Start by creating a custom pipeline component that will remove the filename extension from the ReceivedFileName promoted property.

Here is the entire implementation of the Custom Pipeline Component: 


using Microsoft.BizTalk.Component.Interop;
using Microsoft.BizTalk.Message.Interop;
using System;
using System.Collections;
using System.ComponentModel;
using System.IO;
 
namespace ACME.BizTalkProject.CustomPipelineComponents
{
    [ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
    [ComponentCategory(CategoryTypes.CATID_Any)]
    [System.Runtime.InteropServices.Guid("ba4d77fd-2008-4295-94b6-bd2b2ea7ae0c")]
    public class RemoveExtensionFromReceivedFileNameContextProperty : IBaseComponent, Microsoft.BizTalk.Component.Interop.IComponent, IComponentUI, IPersistPropertyBag
    {
 
        #region IBaseComponent
        string IBaseComponent.Description
        {
            get { return "RemoveExtensionFromReceivedFileNameContextProperty pipeline component"; }
        }
 
        string IBaseComponent.Name
        {
            get { return "RemoveExtensionFromReceivedFileNameContextProperty"; }
        }
 
        string IBaseComponent.Version
        {
            get { return "1.0.0.0"; }
        }
 
        #endregion
 
        #region IComponentUI
        [Browsable(false)]
        IntPtr IComponentUI.Icon
        {
            get { return IntPtr.Zero; }
        }
 
        System.Collections.IEnumerator IComponentUI.Validate(object projectSystem)
        {
            IEnumerator enumerator = null;
            return enumerator;
        }
 
        #endregion
 
        #region IPersistPropertyBag
 
        void IPersistPropertyBag.GetClassID(out Guid classID)
        {
            classID = new System.Guid("ba4d77fd-2008-4295-94b6-bd2b2ea7ae0c");
        }
 
        void IPersistPropertyBag.InitNew()
        {
            // Not implemented
        }
 
        void IPersistPropertyBag.Load(IPropertyBag pb, int errorLog)
        {
            // There are no modifiable parameters. Code below is for sample use only.
            //string val = (string)ReadPropertyBag(pb, "PaddingCharacter");
            //if (val != null) PaddingCharacter = val;
        }
 
        private static object ReadPropertyBag(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName)
        {
            object val = null;
            try
            {
                pb.Read(propName, out val, 0);
            }
 
            catch (ArgumentException)
            {
                return val;
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }
            return val;
        }
 
        public void Save(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, Boolean fClearDirty, Boolean fSaveAllProperties)
        {
            // There are no modifiable parameters. Code below is for sample use only.
            //object val = (object)PaddingCharacter;
            //WritePropertyBag(pb, "PaddingCharacter", val);
        }
 
        private static void WritePropertyBag(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, string propName, object val)
        {
            try
            {
                pb.Write(propName, ref val);
            }
            catch (Exception ex)
            {
                throw new ApplicationException(ex.Message);
            }
        }
 
        #endregion
 
        #region IComponent
        public IBaseMessage Execute(IPipelineContext pc, IBaseMessage inmsg)
        {
            IBaseMessageContext context = inmsg.Context;
 
            if (context != null)
            {
 
                string inFileName = context.Read("ReceivedFileName", "http://schemas.microsoft.com/BizTalk/2003/file-properties").ToString();
                string outFileName = Path.GetFileNameWithoutExtension(inFileName);
 
                context.Write("ReceivedFileName", "http://schemas.microsoft.com/BizTalk/2003/file-properties", outFileName);
 
                pc.ResourceTracker.AddResource(inFileName);
                pc.ResourceTracker.AddResource(outFileName);
 
            }
            return inmsg;
        }
 
        #endregion
    }
 
}

Now add this component to the Encode stage of the send pipeline used by your send port. If you are flattening the file and have a custom pipeline for that , you will want to add the component to the same custom pipeline.

If you need details about how to create and use Custom Pipeline Components, you can find them on MSDN at Developing Custom Pipeline Components

To complete this implementation we need to use the  %SourceFileName% macro on the send port. On your send port, in the FILE Transport Properties window, make the filename %SourceFileName%.txt

Conclusion

Now every message picked up from a FILE location  that is sent to another file location by a pipeline using the custom pipeline component above will retain the original file name with the .TXT filename extension.

See Also

Another important place to find an extensive amount of BizTalk related articles is the TechNet Wiki itself. The best entry point is BizTalk Server Resources on the TechNet Wiki.