Very frequently, in the BizTalk Server newsgroups, I answer questions related to filenames used by the BizTalk Server FTP and FILE adapter. More in particular it seems that for many people it is hard to figure out:
- how to change the FILE/FTP adapter's output file name
- how to acces the FILE/FTP adapter's input file name
Let's change this and dive into the subject a little deeper:
...starting with the more easy thing: the FILE adapter's input and output filename.
When the FILE adapter
receives a message, it promotes context on the message that contains information about the orginal filename. That context is accessible in:
- a custom pipeline (where you'll have to program)
- use the IBaseMessage you get passed by the pipeline framework
- that interface provides you with a context property, which you can use to read promoted properties from
- to give you a feeling, here's a (non-tested!) example:
public IBaseMessage Execute(IPipelineContext pc, IBaseMessage inmsg)
{
//following namespace contains the FILE adapter properties:
const string FILEadapterTargetNamespace = "http://schemas.microsoft.com/BizTalk/2003/file-properties";
// retrieve the inbound file name that was promoted by the FILE adapter:
string sourcePath = inmsg.Context.Read("ReceivedFileName", FILEadapterTargetNamespace ) as string;
return inmsg;
}
- an orchestration (here you have intellisense)
- drop in there an expression shape
- you can access the context of you inbound message, using the context syntax (regular brackets after the messagename with in between the propertyname)
The FTP adapter does same thing upon receival of messages but obviously uses another context property to promote that information on.
It's namespace: http://schemas.microsoft.com/BizTalk/2003/ftp-properties
It's file name context property: ReceivedFileName
So far on the receival side of things, but what about
sending? When sending files, the FILE and FTP differ somewhat in their approach...
Let's start again with the FILE adapter, where you basically have two options when you want to specify the outbound file name:
- Using a static port: specify the outbound file name using one of the supported macro's
This one's easy: the FILE adapter offers you some macros that you can use when binding the BizTalk Server messaging port.
MSDN explains this very well, so I will not go into any details further here... (In addition I remember Jan already posted on this subject as well!) - Using a dynamic port: specify the outbound file name by setting context on the outbound message
Setting context can be done both in a custom pipeline component as well as in an orchestrations expression shape. In any case, when using a dynamic send port in an orchestration, you should set the outbound URL. This can be done in any expression shape (you have intellisense for this). The engine will parse the URL and based upon the prefix (file:// or ftp://) it will use the correct adapter. In addition you may add other context as well (for example specifying the message's retry count).
Setting context using a custom pipeline component is perhaps less straight forward, so let's look into this using a little sample:
IBaseMessage Execute(IPipelineContext pc, IBaseMessage inmsg)
{
//following namespace contains the FILE adapter properties:
const string FILEadapterTargetNamespace = "http://schemas.microsoft.com/BizTalk/2003/file-properties";
// set the the outbound file name for the FILE adapter:
inmsg.Context.Write("ReceivedFileName", FILEadapterTargetNamespace , "myOwnNewFileName.xml");
return inmsg;
}
So... that's it :-) Easy huh! The previous method can as well be used when having a static send port! If you explicitly set the filename in the context the FILE adapter will take this into account and won't use the "default" values specified for that BizTalk Server messaging port.
Now how does this work with the FTP adapter you might wonder? Unfortunately the FTP adapter does not have any macros you can use to set the outbound file name. However both the approach using the dynamic port as well as setting context manually works very well.
For example, inside an orchestration, I might set the location of a dynamic send port like this:
//Set dynamic ports location:
orchprtSndMyMessagePort(Microsoft.XLANGs.BaseTypes.Address) = "ftp://myserver/mydirectory/myfilename.xml";
//Set context on the message you want to send:
msgMyMessage(FTP.UserName) = "myFTPUsername";
msgMyMessage(FTP.Password) = "myFTPPassword";
msgMyMessage(BTS.RetryCount) = 20;
msgMyMessage(BTS.RetryInterval) = 2;
As illustrated, you'll need to specify the username and password for the connection as well. All together I guess this is not a bad approach at all. (Could be more user friendly but once you know, it dóes makes sense, right? In the end, évery adapter gets it's configuration from the message context!)
Very nice, very nice... but, what if you want to be able to transmit files in a particular order, or what if I want to grasp the return value from the FTP adapter's send operation?
There's no way you can grasp the return value of the FTP operation directly. Such kind of things is completely hidden by the adapter itself. BUT there's a way that allows you to know inside your orchestration wether the transmit operation succeeded. This is implemented using a switch on the level of your orchestration's send port, called: "DeliveryNotification". If set to "Transmitted", this will ensure that your orchestration stops working, until the adapter has succesfully transmitted the message. It's the same switch that allows you to send your messages in-order. In addition: if the message fails, an exception will be thrown of type: "XLang.DeliveryFailureException".
So far for files :-) If you have any further questions related to custom pipeline components... watch this blog! I will come back on this subject, showing you some
very cool things!! (Obviously the newsgroups are still there as well.)
Have a nice day!