none
Set the file name from within BizTalk Mapper?

    Question

  • Hi,

    I need to generate an output file from BizTalk 2006 with å dynamic filename based on values in the incoming xml file.
    The best solution for me would be to create a custom Functoid for setting the filename within the BizTalk Mapper.

    My requirements:
    - I don't want the filename exposed as an element or attribute within the xml
    - I don't want to use orchestrations
    - I do use a File adapter
    - I may create a custom pipeline
    - I may create a custom Functoid

    Is there a way of setting the ReceivedFileName in the BaseMessageContext from within a custom Functoid?


    I tried this:
    I tried to set the filename in a custom Functoid, and expose the filename as static, and then pick it up in a custom send pipeline. In the pipeline I replace the ReceivedFileName in the BaseMessageContext, and then used %SourceFileName% in the File adapter.
    The problem was that the file name was static, and therefore shared between all messages going through the BizTalk server.
    I also tried to expose it as [ThreadStatic], but it doesn't seem like the Functoid and the outgoing custom pipeline was in the same thread.

    regards 
    Jimbo Man
    Friday, September 26, 2008 10:45 AM

Answers

  • I think you have the right idea.  The problem with setting the filename in a map is that you really only have access to the message XML.  Since you don't want to put the filename in as an XML element, then it becomes difficult.  I think a better approach would be to calculate the filename in a custom outbound pipeline.  You can still use XPath to do the calculation, similar to what you can do in a map, you just have to write code to do it.
    Saturday, September 27, 2008 1:37 PM
    Answerer
  • Try looking at these two functoids (They are in the same dll): http://www.codeplex.com/ContextAccessor - one of them requires that orchestrations are used and the other can be used in a map in the receive port, given a specific pipeline component has been used in the pipeline coming in.

     

    Maybe the code can point you in the right direction?

     

    Other that that, Russ' idea is ok - whatever you want to do in the map, you can probably also do in the pipeline - only exception is that in send pipeline, you only have the outgoing message, so if you need data from the incoming message for the filename, that is not available in the destination document, then you will need to do the work in the receive pipeline instead.

     

    Monday, September 29, 2008 11:03 AM
  • Thanks everyone for giving me inputs. I finally come up with a solution that solved my issues.

    What I needed was to set the outbound File Name from Biztalk Mapper without the use of Orchestration. I needed to do this for many different BizTalk projects with different file formats and different file name patterns/conventions. It was important for me not to make custom Functoids and Pipeline Components for each BizTalk project in the future.


    This is what I came up with:
    I established one project containing:
    - GetContext Pipeline Component
    - GetContext Functoid
    - SetFileName Functoid
    - SetFileNameInContext Pipeline Component


    GetContext Pipeline Component:
    This component expose the context object as a [ThreadStatic] internal object. It makes the context object readable in Biztalk Mapper via the GetContext Functoid (wich is in the same thread).

    This is the similar as Marvin Smit did in his ContextAccessor project. 


    GetContext Functoid:
    Makes it possible to read the context object, retrieved in the “GetContext Pipeline
    Component”, from the Biztalk Mapper. The GetContext method got two parameters (ContextName and ContextNamespace).

    To get the original file name (inbound):
    - “ReceivedFileName” as first parameter
    - “http://schemas.microsoft.com/BizTalk/2003/file-properties”  as second parameter
    - Returns the incoming file name

    To get the active identity  I send in:
    - “ActivityIdentity” as first parameter
    - “http://schemas.microsoft.com/BizTalk/2003/messagetracking-properties” as second parameter
    - Returns the ActivityIdentity (an ident wich is the same in inbound and outbound context).

    This is the similar as Marvin Smit did in his ContextAccessor project. 


    SetFileName Functoid:
    This Functoid will save the new outgoing file name in a database table with “ActivityIdentity” as key.
    The SetFileName method got three inputs parameters (ConnectionString, ActivityIdent and NewFileName).


    SetFileNameInContext Pipeline Component:
    The “IBaseMessage Execute” method will first read the “ActivityIdentity” from the Pipeline Context objects: 
    String activityIdentity = Convert.ToString(pInMsg.Context.Read("ActivityIdentity", "http://schemas.microsoft.com/BizTalk/2003/messagetracking-properties"))

    Than it retrieves the file name from the database table (from where it was set in the “SetFileName Functoid”). 
    It gets the database connection string from “BTSNTSvc.exe.config” in the C:\Program Files\Microsoft BizTalk Server 2006

    In the end it writes the filename to the Pipeline Context objects:
    String SetContextValue = newFileName;
    String SetContextNamespace = "http://schemas.microsoft.com/BizTalk/2003/file-properties";
    String SetContextName = "ReceivedFileName";
    pInMsg.Context.Write(SetContextName, SetContextNamespace, SetContextValue);


    How to use it:
    - Biztalk Mapper: use the “GetContext Functoid” to get the “ActivityIdentity”.
    - Biztalk Mapper: send the “ActivityIdentity” together with the new file name to the “SetFileName
    Functoid”.
    -  “GetContext Pipeline Component” must be in the ResolveParty section in the receive pipeline
    - The “SetFileNameInContext Pipeline Component” must be in the Pre-Assemble section in the send pipeline.
    - Use the %ReceivedFileName% macro in the outbound location.


    /JimboMan
    Wednesday, October 01, 2008 9:27 AM

All replies

  • I think you have the right idea.  The problem with setting the filename in a map is that you really only have access to the message XML.  Since you don't want to put the filename in as an XML element, then it becomes difficult.  I think a better approach would be to calculate the filename in a custom outbound pipeline.  You can still use XPath to do the calculation, similar to what you can do in a map, you just have to write code to do it.
    Saturday, September 27, 2008 1:37 PM
    Answerer
  • Try looking at these two functoids (They are in the same dll): http://www.codeplex.com/ContextAccessor - one of them requires that orchestrations are used and the other can be used in a map in the receive port, given a specific pipeline component has been used in the pipeline coming in.

     

    Maybe the code can point you in the right direction?

     

    Other that that, Russ' idea is ok - whatever you want to do in the map, you can probably also do in the pipeline - only exception is that in send pipeline, you only have the outgoing message, so if you need data from the incoming message for the filename, that is not available in the destination document, then you will need to do the work in the receive pipeline instead.

     

    Monday, September 29, 2008 11:03 AM
  •  

    Ok since yoy don't want to use orchestrations it makes things a bit harder to realize.

    But the easiest way to accomplish thi sis the following.

     

    1. Create a proeprty schema that contains the fields you want to use for the filename.

    2. Make sure they are context properties (MessageContext)

     

    deploy the schema's

     

    then create a custom Send pipeline component. And make sure you get the proeperties from the context, construct your own filename and make sure you populate the context property ReceivedFileName.

     

    Then use a macro in the outbound location like this %ReceivedFileName% and you are done.

     

    By putting the values you need on the context you let BizTalk take care of finding out the values and populating them. So you don't have to worry about executing xpath statements......

     

    Tuesday, September 30, 2008 6:51 AM
  • Hi,

    I don't want to know anything about the outbound xml, and cannot put the filename in a xml node or attribute.
    Thanks anyway.

    I think I found a solution for my problem, and I will post it as soon as it tested.

    /JimboMan
    Wednesday, October 01, 2008 7:30 AM
  • Thanks everyone for giving me inputs. I finally come up with a solution that solved my issues.

    What I needed was to set the outbound File Name from Biztalk Mapper without the use of Orchestration. I needed to do this for many different BizTalk projects with different file formats and different file name patterns/conventions. It was important for me not to make custom Functoids and Pipeline Components for each BizTalk project in the future.


    This is what I came up with:
    I established one project containing:
    - GetContext Pipeline Component
    - GetContext Functoid
    - SetFileName Functoid
    - SetFileNameInContext Pipeline Component


    GetContext Pipeline Component:
    This component expose the context object as a [ThreadStatic] internal object. It makes the context object readable in Biztalk Mapper via the GetContext Functoid (wich is in the same thread).

    This is the similar as Marvin Smit did in his ContextAccessor project. 


    GetContext Functoid:
    Makes it possible to read the context object, retrieved in the “GetContext Pipeline
    Component”, from the Biztalk Mapper. The GetContext method got two parameters (ContextName and ContextNamespace).

    To get the original file name (inbound):
    - “ReceivedFileName” as first parameter
    - “http://schemas.microsoft.com/BizTalk/2003/file-properties”  as second parameter
    - Returns the incoming file name

    To get the active identity  I send in:
    - “ActivityIdentity” as first parameter
    - “http://schemas.microsoft.com/BizTalk/2003/messagetracking-properties” as second parameter
    - Returns the ActivityIdentity (an ident wich is the same in inbound and outbound context).

    This is the similar as Marvin Smit did in his ContextAccessor project. 


    SetFileName Functoid:
    This Functoid will save the new outgoing file name in a database table with “ActivityIdentity” as key.
    The SetFileName method got three inputs parameters (ConnectionString, ActivityIdent and NewFileName).


    SetFileNameInContext Pipeline Component:
    The “IBaseMessage Execute” method will first read the “ActivityIdentity” from the Pipeline Context objects: 
    String activityIdentity = Convert.ToString(pInMsg.Context.Read("ActivityIdentity", "http://schemas.microsoft.com/BizTalk/2003/messagetracking-properties"))

    Than it retrieves the file name from the database table (from where it was set in the “SetFileName Functoid”). 
    It gets the database connection string from “BTSNTSvc.exe.config” in the C:\Program Files\Microsoft BizTalk Server 2006

    In the end it writes the filename to the Pipeline Context objects:
    String SetContextValue = newFileName;
    String SetContextNamespace = "http://schemas.microsoft.com/BizTalk/2003/file-properties";
    String SetContextName = "ReceivedFileName";
    pInMsg.Context.Write(SetContextName, SetContextNamespace, SetContextValue);


    How to use it:
    - Biztalk Mapper: use the “GetContext Functoid” to get the “ActivityIdentity”.
    - Biztalk Mapper: send the “ActivityIdentity” together with the new file name to the “SetFileName
    Functoid”.
    -  “GetContext Pipeline Component” must be in the ResolveParty section in the receive pipeline
    - The “SetFileNameInContext Pipeline Component” must be in the Pre-Assemble section in the send pipeline.
    - Use the %ReceivedFileName% macro in the outbound location.


    /JimboMan
    Wednesday, October 01, 2008 9:27 AM