|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionSome time ago, I was developing a solution using Biztalk server and found very little information about how to call a web-service (or any other process) asynchronously. After doing some search in the Biztalk documentation, I found an interesting solution that consisted of two orchestrations and a port that is passed from one orchestration to the other as a parameter. To illustrate this solution, I'll use a hypothetical situation using the Northwind database. The scenarioLet's say that you are working for a big company, and the company works with a legacy system to process orders. The company is now planning to replace the system, but it will take 1 year until the new system is ready to be run. The company is currently using Biztalk as its integration platform, and you are working as a Biztalk developer. Since your company needs to expand its business and can't wait until the new system is ready, your boss comes to you with a new task. "Our querying support to our legacy system is very limited. Today our salesperson can only query orders from a single day, and not from a range of dates. This information is critical to us because in order to increase our sales, our sales staff needs to have information about an entire month or even an entire year, in order to analyze trends. I need you to create a Biztalk process capable of receiving a range of dates and querying our legacy system for each day in that range. This biztalk process will return all the orders from that range as a result". Sounds like an easy task to Biztalk, isn't it ? Lucky for you, the guys from the legacy system have created a web service layer so that you can query orders from a specific day in the legacy system. To simulate the legacy system's web service, I have created a simple web service that queries the information in the Northwind database. The source code of the web service is available in the article. The architectureBefore we start constructing the biztalk solution, we need to understand how our order querying process will work. The diagram below shows the how the solution will work:
The process starts when the end user application sends an XML request to the Biztalk server. This request will have the date range that we need to query in our legacy system. When the message hits biztalk, it spawns one instance of another orchestration for each date in that range (in the diagram there is an orchestration instance to 7/1/1996, 7/2/1992, 7/3/1996 and 7/4/1996). This second orchestration uses the web service from the legacy system to query the orders for a specific date. Note that all such orchestrations are spawned asynchronously. As soon as each orchestration finishes its processing, it will return the response to the main orchestration. Note that as soon as the loop finishes in the main orchestration, we start another loop, waiting for the responses of each orchestration that we have spawned. After we receive all the messages, we aggregate them into a single one and return to the end user application. Using this approach, the time that it takes to query a range of dates will be nearly the same as querying a single day, since our orchestration spawns a new query to the legacy system at the same time for each day. Since we don't have an end user application, we'll use XML files to simulate the end user application. Creating the projectWe'll start by creating our biztalk project. Start Visual Studio and create a new Biztalk server project named BTSOrderQuery. You need to add two references to the project. The first is a reference to the BTSUtils library. This library contains a generic class that is used to aggregate XML messages. You can find this project in the ZIP file available with the article. The other reference is a web reference to the web service of our legacy system (also available for download in a separate .zip file). Just click on references, add a web-reference and type the URL where you have installed the web-service (in my case it is http://localhost/legacyorder/orderquery.asmx). Creating the schemaThe first item we will create in our project is the schema used to send a query request to the Biztalk server. Right click on the project in the Solution Explorer and select the "Add New Item..." option. Select schema as the item type and name it as OrderRequest.xsd. Open the schema that you have just created (if it's not already open) and change its "Target Namespace" property to "http://nwtraders" (click on <Schema> to access this property). After changing the target namespace, change the "Node Name" property of the root element to OrderRequest. Now, add two child fields in the root element (right click on the "OrderRequest" element and select "Insert... Child Field Element") named To finish our schema, right-click on
Promoting these fields as "Distinguished Fields" will allow us to access them inside the orchestration code. At the end of the process, your schema should look like the one shown below:
Creating the main orchestrationNow that we have our schema and the references, we're going to create the main orchestration. Right click on the project, select the "Add New Item..." option and select "Orchestration". Name it "OrderRequestMain". Open the Orchestration View window (if you don't see the orchestration view window, go to the "View" menu, "Other Windows", and select "Orchestration View") and right click on the messages folder, and select the "New Message" option. Change the name of the message to " From the toolbox, drag a receive shape to the orchestration designer area and name it " In the orchestration view, right click on the variables folder and select "New Variable". Name the variable as " System.DateTime.Compare(dtDate, msgOrderRequest.EndDate) <= 0
Now add a "Start Orchestration" shape inside the loop shape and an "Expression" shape below it (inside the loop shape as well). In the expression shape, add the following expression: dtDate = dtDate.AddDays(1);
Copy the first expression shape in the orchestration and paste it just below our loop (this will reset the date variable to our new loop). Now drag another loop shape and use the same expression property that we used in the other loop. Inside this loop, add a receive shape and an expression shape. In the receive shape, select oAgreg.Aggregate(msgOrders.GetOrdersResult,
"/ns0:Result/ns0:Orders", "/ns0:Result/ns0:Orders/ns0:Order");
The expression above uses the generic aggregator to combine the results of each day into one message. To finish our main orchestration, drag a "Message Construct" shape below the last loop we've created. Select the msgOrders.GetOrdersResult = oAgreg.GetAggregatedDocument();
The At this point, your orchestration should look like the picture below:
Creating the portsNow, we need to create the ports to receive and send our messages. Right click on the port surface on the left side of the orchestration designed and select "New Configured Port". Click next on the first screen. In the next screen, type "rpIN" as the name of the receive port and click next. Let's create the second port (the one that will receive the messages from the other orchestration). Right click on the port surface, now on the right side of the orchestration and select "New Configured Port". Click next on the first Screen. In the next screen, type "rpOrders" as the name of the receive port and click next. In the next screen, type "rpOrdersType" as the port type and click next. Make sure that the "I'll always be receiving..." option is selected, and select "Direct" as the "Port Binding" option. In the direct binding options, select "Self Correlating". Click next and then finish. We use the self correlating option here biztalk, we're going to pass this port as a parameter to our other orchestration (yeikes!), and by selecting this option we make sure that the response will be directed to the correct orchestration. Connect this port to the receive shape inside the second loop. Now for the last port. Right click on the port surface on the left side of the orchestration designed and select "New Configured Port". Click next on the first screen. In the next screen, type "spOUT" as the name of the receive port and click next. In the next screen, type "spOUTType" as the port type and click next. Make sure that the "I'll always be sending..." option is selected, click next and then finish. A new port will be created. Connect this port to the last send shape in the orchestration. After creating the ports, our orchestration should look like this.
Creating the second orchestrationThe second orchestration is responsible for querying our legacy system's web service for a specific date and returning the result to the main orchestration. This second orchestration is simpler than the first one. Let's start by creating a new orchestration file. In the Solution Explorer, right click on the biztalk project and select "Add New Item...". Select "Orchestration" and name it "BTSQueryLegacy". As opposed to other orchestrations, this one will be activated by parameters and not by a receive shape. Go to the orchestration view and right click on the "Orchestration Parameters" option. Select "New Variable Parameter". Change the parameter's name property to In order to call the legacy web service, we need to create request and response messages. Create messages in the "Orchestration View" window called Now let's add some shape to the orchestration. Drag a message construct shape to the orchestration and select the " msgReq.date = dtOrder;
This will create a request message with the order date received as parameter. Now drag a send shape below the message construct and select " Using a port parameterNow we need to send the response back to the main orchestration. To to this, we'll use a port parameter. Select the "New Configured Port Parameter", click next on the first screen. In the next screen, select Passing a port as a parameter to another orchestration is the only valid situation where you can change the "polarity" of the port, change it from a receive port to a send port. The concept used here is very similar to a callback function. We pass a receive port from the main orchestration to the specific orchestration (callback function). When the specific orchestration finishes its work, it sends its response to the port received as a parameter (call the callback function to notify the caller). Drag a send shape below the last receive shape in the orchestration and select
Final stepsThe only thing that is missing is a property in one specific shape in the main orchestration, the start orchestration shape. Open the main orchestration and find the start orchestration shape. In the "Called Orchestration" property, select " In order to test our solution, you need to create a strong name for the biztalk assembly. You can do this by using the sn.exe tool. After doing this, deploy the solution to your biztalk server and then create receive and send ports using the FILE adapter in order to test our solution. I used the following message to test the solution: <ns0:OrderRequest xmlns:ns0="http://nwtraders">
<StartDate<1996-07-04T00:00:00.000-00:00</StartDate>
<EndDate<1996-07-10T00:00:00.000-00:00</EndDate>
&</ns0:OrderRequest>
The resultIf you drop a test message in your file receive port (you can use any date between 7/1/1996 and 7/30/1996), biztalk will drop in the out folder a message with the consolidated result. If you check Health and Activity Monitoring (HAT) when you drop the file, you'll see that the main orchestration really spawns another orchestration for each date in your Order Query request, as shown in the image below:
And that's how you can make asynchronous calls using biztalk. Using two orchestrations and passing a port as parameter solves all the problems. Hope you liked the article! :)
|
||||||||||||||||||||||