|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
Contents
IntroductionBizTalk Server 2006 has around 80 functoids, or functions, these functoids are helpful while building your maps; more about that later. BizTalk Server 2006 Mapper IDE is the same as VS.NET 2005 IDE; when you build a map you will be inside the same environment that you are used to, and if you open a map, the functoids toolbox will display all standard and custom functoids, the standard functoids are categorized in a neat way based on the functionality of each, but sometimes the functoids library you have is not enough, so you will opt to build your own functoid, in this article, I will give you an introduction about BizTalk Server 2006 Mapper, and I will try to explain and boil down the standard functoids provided by BizTalk Server 2006, giving one practical example about Database Lookup functoid, then we'll go through building a custom functoid after we examine the architecture of custom functoids; the functoid we'll build is a Currency Converter functoid, I tried to propose a useful and reusable functoid that you may use later, this functoid is built upon a web service that provides currency rates, Also you will learn how to install your functoid into the GAC ( Global Assembly Cache ), and add it to your toolbox, so let's start our journey with functoids. Knowledge Prerequisites and Software Requirements
BizTalk Server 2006 MapperBizTalk Mapper is just a tool to define relationships between an input source schema and a destination schema, in other words it binds elements, attributes, records, etc.. to one another using a polished designer, right inside VS.NET 2005, you can directly connect one field element to any other schema element, or you can process the input data then you send it to the destination element; the processing is maintained using Functoids, for example if the destination schema allows only Name field element, while the source schema has two fields for the name, one is the firstName, second is the lastName, you can use a String Concatenate functoid, that accepts first and second names, it actually accepts from 1 to 100 parameters, then you can create a link from this functoid output to the destination schema element, which is Name in this case. BizTalk saves a map in a .btm ( BizTalk Map ) file extension, and this is an XML based file, if you are curious, like me, open it in any XML editor or even in notepad, you will find out that everything about the map is stored inside, you will find XML nodes and elements about everything on the design surface, including Links, Functoids, Input Parameters, Pages, Source and Destination schemas, etc.., Pages are design pages that you use when your map gets sort of spaghetti, and you need to organize your links, it's a good practice to keep direct links in one page, and functoid based links in another page, this would be more comprehensive, and once your map is built, it's getting converted to XSLT file; a link is provided at VS.NET output window you can open the XSLT file and view its contents. Fig01 : BizTalk Server 2006 Mapper Basically, maps are used for two purposes Translation and Transformation of Messages, Translation is just about Message Format, while Transformation is all about Data, in other words; when you use a map to change the format of a message from one to another you are doing Translation, consider translating one message from flat file format to XML format, Transformation is copying data between schemas using maps, if you have one source schema that contains a Salary data element, and you need to copy this salary value from Human Resources department application to another department such as Finance, this is what we mean by Transformation. BizTalk Server 2006 Standard FunctoidsIn this section I will give a brief about Standard Functoids included in the Functoids toolbox, some functoids are self-explanatory while others somehow need some clarification
Cross Referencing Functoids , these functoids use data stored in BizTalkMgmtDb, The Configuration wizard creates these tables during configuration, you can find them in the BizTalkMgmtDB database; they are 9 tables prefixed with xref_ , but the tables stay empty until you fill them out from 9 XML files, this will get the database tables filled in, and if you don't fill these table you will not be able to use this set of functoids, if you try you will get exceptions. Functoids ConfigurationAs we have seen above a functoid takes some input parameters; these parameters need to be configured, to inform the functoid how to operate based on these input parameters, in the following section we'll view a simple example that looks up some data from a database, based on one ID passed, so we'll use Database Lookup Functoid, with Value Extractor and also we'll add the Error Return functoid to the map to demonstrate how to use these three functoids together. Let's say that you have a group of stores, that are managed only by one headquarter, and this headquarter can send a PO to any affiliate that could get merchandise from a store specified by the headquarter, all communication is only between the headquarter and the affiliate, so the headquarter schema lookup the database by passing the StoreID, from which affilate will collect merchandise, to a Database Lookup functoid, and then to extract data to be sent to affiliate, we will start using Value Extractor functoid to extract specific field value from returned recordset, and for handling unexpected errors like syntax and connection failures or timeout, we'll add an Error Return functoid that will write the exception details to the destination schema. For the sake of simplicity we'll use the Pubs database, and we will lookup Stores table. You will need to create two schemas, first is Headquarter.xsd and the second is Affiliate.xsd, then you will need to create a new map call it Affiliate.btm, details for the schemas and the map are shown in the following screen Fig02 : Affiliate Map, source is Headquarter schema and destination is Affiliate schema Now, you should configure the functoids added to the map, for this example we'll configure the database lookup functoid, you can double click it, or select the input parameters from the properties window, you will get the modal dialog box, Configure Functoid Inputs, and you will get a good description about the number of parameters to be added, if you try to add more you will not be able to do so, as once you reach the number of allowed input parameters the new input parameter button gets disabled. Fig03 : Configuration of input parameters for Database Lookup Functoid The first parameter is the expression to extract lookup value from source schema and it is built by Mapper, second is the database connection string, and it's strongly recommend to use windows integrated security, third is table name, fourth is the column name, you can configure the rest of functoids easily, Value Extractor functoid will take only the column name, it will extract the value of one column from the database lookup functoid. After building schemas, maps, now you need to build an input file to provide to Affiliate map to be tested, we'll build a simple XML file, call it Headquarter.xml and these are the contents of the file ( included in code download ). <ns0:Headquarter xmlns:ns0="http://FunctoidConfigurations.Headquarter"> <Store StoreID="StoreID_0" /> </ns0:Headquarter> Now, we need to provide this file to the map to let the map use it while testing, right click Affiliate.btm from solution explorer and select Properties, this will open the map property pages, Select TestMap Input file and browse to Headquarter.xml. Now, you are ready to test your map, right click the Affiliate.btm from solution explorer and select Test Map , after few seconds you will get some output messages at the output window, and you will get a link to input and output files generated after testing the map, if you open the output file it should be like this <ns0:Affiliate xmlns:ns0="http://FunctoidConfigurations.Affiliate"> <Store StoreName="" Zip=""> <StoreAddress></StoreAddress> <City></City> <State></State> <ErrorMessage></ErrorMessage> </Store> </ns0:Affiliate> As you see the output is empty since we don't have in the stores table one store id value "StoreID_0", now we willl change the StoreID value in source schema to "6380"; this is a value that exists in Stores table, then we can test again, this time you will get the details of store id 6380 <ns0:Affiliate xmlns:ns0="http://FunctoidConfigurations.Affiliate"> <Store StoreName="Eric the Read Books" Zip="98056"> <StoreAddress>788 Catamaugus Ave.</StoreAddress> <City>Seattle</City> <State>WA</State> <ErrorMessage></ErrorMessage> </Store> </ns0:Affiliate> As you can see, the Database Lookup Functoid extracted all the fields for the input store id, in case the recordset includes more than one record; the first matching records is the one that's used. Now, we'll force the Database Lookup functoid to throw an exception, simply go to the Configuration of Database lookup functoid and append 'X' to the database table name, now the database table name is 'storesX', try to test the map again ,and let's see what will happen, open the output file you will get this XML output <ns0:Affiliate xmlns:ns0="http://FunctoidConfigurations.Affiliate"> <Store StoreName="" Zip=""> <StoreAddress></StoreAddress> <City></City> <State></State> <ErrorMessage>Invalid object name 'storesX'.</ErrorMessage> </Store> </ns0:Affiliate> Since, the table name is invalid, you will not get any data into the destination schema, and you will get a meaningful error message that explains the reason behind getting no data, so it's advisable to use Error Return Functoid! Custom Functoids ArchitectureNow, we are done with the standard functoids, and we will move to another stage of functoids; building a custom functoid, basically you opt to this solution when you don't find a a standard functoid that covers your needs. The functoid that we are going to build is a Currency Converter Functoid, and here we should mention some words about what the functoid should and shouldn't do, when to use it and not to use it, actually this has been an architectural argument among technology specialists, some say maps are just about mapping and no business processing should be done inside maps, and all data processing should be done at orchestration, while the others encourage and support processing data at the map level, and their evidence is the standard Database functoids included in the functoids group, however you should decide when to use a custom functoid and whether it will affect performance heavily, it's simply a matter of design and performance too, but for this CurrencyConverter functoid, I think it's helpful and it's right to encapsulate this functionality inside one reusable functoid, for the above example we can send to Affiliate the store currency, supposing stores are distributed around the globe, and also the rate of this local currency in USD, here the importance of our custom Currency Converter functoid comes to light!, actually I have seen around some EAI solutions require currency conversions. Functoids are just a .NET compiled code included, of course, inside one or more assemblies, custom functoid should inherit from a BaseFunctoid class that's contained in Microsoft.BizTalk.BaseFunctoids namespace, this namespace maps to one assembly which is Microsoft.BizTalk.BaseFunctoids.dll, located at Developer Tools folder under your installation folder, to create a custom functoid we'll override some overridable methods in the base class. Custom Functoids DesignLet's examine what we've done in the above Database Lookup Functoid, to know what we'll need to create our Currency Converter Custom Functoid, before you drag a functoid to a design surface, you first spot a category under which your functoid located, then you find your functoid Name, preceded with a 16x16 Bitmap, once you move your mouse over it you get a tooltip, also you will need to supply a Description to your functoid, you will need to supply one ID, greater than 6000 as recommended by Microsoft, the description is so important and I strongly recommend that elaborate as much as you can, I tried to provide a description similar to standard functoids descriptions. Once you place the functoid into the design surface, the user will start to provide Input Links, so we need to define Minimum and Maximum Number of Input Parameters, functoids accept specified types of input parameters and outputs to specified types of schema elements, so we also need to define acceptable Input Connection Types, and Output Connection Types, at runtime the mapper calls your functoid so you should provide one name to the mapper that identifies your functoid, and this is mandatory for functoids that are planned to be deployed into GAC, you assign this name by calling SetExternalFunctoinName, so this sets an External Name for your custom functoid. That was for the class that will encapsulate the functoid as a component, but for the implementation we will need to refer to the webservice that will provide the currency conversion, also we will need to build a resource file to hold strings and bitmaps required for the functoid. You can check the webservice at CurrencyConverter, we are going to add a web reference to this webservice, the WSDL contract is available at Currency Converter WSDL, as we'll deploy the functoid into GAC, we need to provide a strong name key file to it, or to digitally sign our assembly, so we'll need to create an SNK file, which we will discuss in the following section. Currency Converter Functoid DevelopmentIn this section we will build our functoid, we will write code, draw a bitmap, build a resource file, and create a new SNK file, this section is kind of a walkthrough. Create a new Class Library Project, and name it BusinessFunctoids, rename the default class file to CurrencyConverter.cs, first we will add all the normal and web references we need to develop our functoid. Adding Required ReferencesAs mentioned earlier that our class will inherit from BaseFunctoid class, this class belongs to Microsoft.BizTalk.BaseFunctoids.dll assembly, you can locate it at C:\Program Files\Microsoft BizTalk Server 2006\Developer Tools, or it should be under Developer Tools installation folder, you can add a reference to this assembly by right clicking references from Solution Explorer and add a reference to this assembly so you will be able to use BaseFunctoid class. To consume CurrencyConverter webservice you will need to add a web reference to your project, you can do that by right clicking your BusinessFunctoids class library project and selecting Add Web Reference, this will bring the Add Web Reference Window, you should enter the URI of the CurrencyConverter Webservice which is http://www.webservicex.net/CurrencyConvertor.asmx?WSDL, now you are ready to start developing your custom functoid. Creating Strong Name Key FileTo Deploy our Currency Converter Functoid into GAC, we need to digitally sign the assembly to expose it to the entire system, however in VS.NET 2003 you had to run the Visual Studio Command Prompt from Visual Studio.NET Tools, and you could use sn command, this way still works in VS.NET 2005. to create a new snk file, open the VS.NET command prompt and type sn -k BusinessFunctoids.snk This will create the snk file to the location where you run the command from; if you are at C:\ and you run your command the file will be written to C drive, now you need to expose your snk file to the class library project; right click BusinessFunctoids project from Solution Explorer, select Properties, select Signing Tab from the left panel, check Sign the assembly, from the dropdown list you can browse and select the file you've created using the above command, or you can select New to create a new SNK file right from VS.NET 2005 and directly associate it to the project, the later way is more elegant. Building Assembly Resource FileTo provide resources to Currency Converter functoid , we need to create a new resource file that will hold all the strings needed for Currency Converter Functoid, and also it will hold a 16x16 bitmap icon for the functoid, one odd thing about VS.NET resource designer is that it only supports string manipulations and if you want to add a picture to the resource file; it will not allow you to do so, so I often use an external tool to add a bitmap to a resx file, it's Resource Editor.NET, another stunning tool provided by CodeProject community member! , open the resx file and supply these values, then add currencyicon.bmp to the resx file, the description tells everything about the functoid, how many parameters required and explanation about parameters.
CurrencyConverter Functoid ImplementationIn this section we'll write the code for our functoid, our code is divided into two sections; first is the functoid constructor, that calls the base constructor, and its objective is to define the functoid to the mapper toolbox, let's examine the constructor code 1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 using Microsoft.BizTalk.BaseFunctoids; 5 using System.Reflection; 6 using System.Globalization; 7 using BusinessFunctoids.net.webservicex.www; 8 9 namespace BusinessFunctoids 10 { 11 ///<summary> 12 /// CurrencyConverter inherits BaseFunctoid 13 ///</summary> 14 publicclassCurrencyConverter : BaseFunctoid 15 { 16 ///<summary> 17 /// This is the defualt constructor that conveys to the toolbox. 18 ///</summary> 19 public CurrencyConverter() 20 : base() 21 { 22 this.ID = 6500; 23 // this to get the resources embedded in the resx file, //and we call GetExecutingAssembly because 24 // the resource is compiled and embedded into the DLL. 25 SetupResourceAssembly("BusinessFunctoids.BusinessFunctoidResources", Assembly.GetExecutingAssembly()); 26 27 // Setting the functoid with resources inside resx file 28 SetTooltip("IDS_CURRENCYFUNCTOID_TOOLTIP"); 29 SetBitmap("IDI_CURRENCYFUNCTOID_ICON"); 30 SetName("IDS_CURRENCYFUNCTOID_NAME"); 31 SetDescription("IDS_CURRENCYFUNCTOID_DESCRIPTION"); 32 33 // Accepts 3 Params, source currency, destination currency, price. 34 this.SetMinParams(3); 35 this.SetMaxParams(3); 36 37 // this method call lets the mapper what function to call, when functoid 38 // is deployed to GAC, ConvertCurrencyField is the method we'll include later. 39 SetExternalFunctionName(GetType().Assembly.FullName, "BusinessFunctoids.CurrencyConverter", "ConvertCurrencyField"); 40 41 // defining category in toolbox, //this decides under which category the functoid will be added. 42 this.Category = FunctoidCategory.Conversion; 43 44 //define output and input connection types.. 45 this.OutputConnectionType = ConnectionType.AllExceptRecord; 46 AddInputConnectionType(ConnectionType.AllExceptRecord); 47 48 }The code is self-explanatory, in line 22 you supply the ID to our functoid, code from 28-31 sets resources required for the toolbox, 34-35 to decide how many parameters valid for the functoid, 39 sets the external function name, 42 assigns the category under which the functoid will appear, 45-46 set output and input connections types. Line 25, calls SetupResourceAssembly base method that takes 2 parameters, first is the resource file name, second is the assembly. The following section demonstrates the concrete functoid logic, that converts one input field from one currency to another using the CurrencyConverter webservice 50 public string ConvertCurrencyField(string fromCurrency, string toCurrency, string field) 51 { 52 decimal numericField,result = 0m; 53 double rate; 54 55 if (IsNumeric(field)) 56 { 57 try 58 { 59 numericField = Convert.ToDecimal(field, System.Globalization.CultureInfo.InvariantCulture); 60 BusinessFunctoids.net.webservicex.www.CurrencyConvertor ws_Converter; 61 ws_Converter = new BusinessFunctoids.net.webservicex.www.CurrencyConvertor(); 62 63 rate = ws_Converter.ConversionRate( 64 (BusinessFunctoids.net.webservicex.www.Currency) Enum.Parse(typeof(BusinessFunctoids.net.webservicex.www.Currency), fromCurrency), 65 (BusinessFunctoids.net.webservicex.www.Currency) Enum.Parse(typeof(BusinessFunctoids.net.webservicex.www.Currency), toCurrency) 66 ); 67 68 result = Convert.ToDecimal(rate) * numericField; 69 70 } 71 catch (Exception ex) 72 { 73 throw ex; 74 } 75 } 76 return result.ToString(); 77 } The above method is the core method, it's the functoid that will process everything, it's designed to take 3 parameters fromCurrency, toCurrenty, and field; the field is the amount or number to be converted, and you should consider that everything is a string in terms of the mapper, that's why we pass strings to our functoid, the mapper doesn't manipulate data types conversion, moreover the arguments should be strings, and the return as well, the function should be public to let the mapper call it, from inside you should check for the data type of input arguments, it's sort of more data type verification because the schema validates the input values based on the schema definition. The code is self-explanatory and you should know from WSDL and provided examples in webservice's website that it expects currencies in ISO format, and there is a Currency Enumerator that holds all supported currencies, it's better to hold code between try-catch block since we're calling an external webservice, lines 63-66 makes a call to the webservice passing the enumerated currency codes, then we have the rate, which is the most important value we need, line 68-69 calculates the field in destination currency as per the rate value, then we return the value after casting it to string. Congrats !, you've finished developing your Currency Converter Functoid, and the remaining sections are focused on deployment, and testing the functoid. Adding Currency Converter Functoid to ToolboxWhen Mapper starts it checks one folder to and loads any functoids assemblies inside this folder, this folder is Mapper Extensions folder under Developer Tools folder, you need to copy your built functoid assembly BusinessFunctoids.dll to this folder, now you can add Currency Converter functoid to VS.NET functoids toolbox, open a map in VS.NET to get Functoids toolbox, then from Tools menu select Choose Toolbox Items, select Functoids tab, then browse to the Mapper Extensions folder in which you've copied BusinessFunctoids.dll before, select BusinessFunctoids and press OK, you will get the icon of CurrencyConverter functoid in the lower part of the window, click OK, focus will go to Currency Converter functoid under Conversion category. Registering Currency Converter Functoid to GACCurrency Converter is a global functoid that will be called by mapper so we need to deploy it to Global Assembly Cache using the VS.NET 2005 command prompt, open VS.NET 2005 command prompt and browse to Mapper Extensions folder and enter the following to register Currency Converter functoid into global assembly cache gacutil /if BusinessFunctoids.dll If the process goes smoothly, you will get Assembly Successfully added to the cache , if you want to assure that the assembly is added to the GAC, browse to Windows Installation directory and then to assembly directory, try to spot BusinessFunctoids assembly, if it's there so everything is fine, and the assembly is physically installed in the GAC. Currency Converter Functoid ConsumptionNow is the time to use the currency converter functoid, we'll create two schemas and one map, suppose that an exporter is selling products to foreign importers, the exporter is supposed to send the prices in foreign importer currency, for this purpose you will need to create a new empty BizTalk Server project call it CurrencyFunctoid, and add a new schema file, call it ExporterSchema.xsd and rename the root node to ExporterOrder, right click this node and select Insert Schema Node -> Child Record, rename it to Order and set Min Occurs and Max Occurs properties to 1, right click Order node and select Insert Schema Node -> Child Record, rename it to Item and set Min Occurs to 1 and Max Occurs to * (unbounded), then add the following fields to Item record
Add a new schema file to the project, call it ImporterSchema.xsd, rename the root node to Order, right click this node and select Insert Schema Node -> Child Record, rename it to Item and set Min Occurs to 1 and Max Occurs to * (unbounded), add the following fields to the Item record
Fig04 : Configuration of input parameters for Currency Converter Functoid <ns0:ExporterOrder xmlns:ns0="http://CurrencyFunctoid.ExporterSchema"> <Order> <Item currency="USD" foreignCurrency="EGP"> <price>10.4</price> <quantity>10</quantity> <productCode>productCode_0</productCode> </Item> </Order> </ns0:ExporterOrder>The input currency is USD and destination currency is EGP (Egyptian pound), suppose the exporter in United States and the importer at Egypt, to provide this input test file to the map, right click CurrencyConversion.btm from solution explorer, select Properties, select TestMap Input Instance, click ellipsis button and browse to Map_test_Input.xml, click Open and then OK, right click CurrencyConversion.btm map from solution explorer and select Test Map, the output window will show and after testing the map you will get a link to an output file in the output window, press CTRL+Click to open it in VS.NET, you will get the following output message <ns0:Order xmlns:ns0="http://CurrencyFunctoid.ImporterSchema"> <Item PId="productCode_0"> <quantity>10</quantity> <price>59.7272</price> </Item> </ns0:Order>Congrats, the price is in foreign currency, if you divide 59.7272 by 10.4 you will get 5.743 which is the rate of USD against Egyptian pound. Using CodeCode download contains one solution CurrencyFunctoid, and three projects, first is class library BusinessFunctoids that contains the CurrencyConverter functoid, second is CurrencyFunctoid that serves as a test application for the custom CurrencyConverter functoid, third is FunctoidConfigurations, this is the Database Lookup functoid example we derived above. Points of InterestsFor our Currency Converter functoid we only considered GAC functoid, that should be deployed to GAC, however we have got another option to build a functoid it's called Inline Script Functoid, in this approach you expose your functoid code, that's .NET code, to the mapper and during runtime the Mapper embeds the functoid code into the map, while this has an advantage of being independent on the GAC assembly, but it has disadvantage that you embed the code into the map. Currency Converter Functoid depends on the Currency Converter Webservice, if any interface changes, which is rare to happen, you should take care about that. ConclusionYou have learnt how to use standard functoids, and we have gone through an example about consuming Database Lookup functoid, also you have built a GAC Currency Converter custom functoid that's consuming a Currency Converter Webservice.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||