Introduction

In the first part of the article, we discussed the advantages and disadvantages of Dynamic Send Ports and we introduced two custom components that allow, respectively, to use Static Send Ports instead of Dynamic Send Port with an ESB Itinerary and to speed up message transformation. In this post I will move into detailing the test scenarios that I built to measure and compare performance of standard and custom Routing and Transform Services, while in the third part I’ll provide results and I’ll show how using profiling tools (Visual Studio Profiler and SQL Server Profiler) to narrow down and determine the cause of performance problems.

Test Use Cases

In order to verify that my custom Routing and Transform components were working properly and to measure and compare performance with those of the equivalent Routing and Transform services provided out-of-the-box by the ESB Toolkit 2.0, I created 3 different scenarios composed of 8 test use cases all belonging to the same BizTalk application called ESB.Itinerary.Services. A secondary objective was to observe and analyze the runtime behavior of Dynamic Send Ports in order to verify that certain Adapters like the WCF-Custom Adapter behave in a different way with respect to when they run in Static Send Port. In order to generate traffic against test use cases, I used Visual Studio 2008 Test Edition. For more information on this topic, you can review the following article:

  • Using Visual Studio 2005/2008 To Generate Load Against a Two-Way Request-Response WCF Receive Location” available on my blog.

  Note
All the Receive Locations used by test cases have been configured to run within a different host (BizTalkServerReceiveHost64) other than the host (BizTalkServerSendHost64) used to execute Send Ports.

 

Scenario 1

The main objective of the first scenario was measuring the performance of the 4 possible combinations of the custom and out-of-the-box (here indicated with the  prefix OOB) Routing and Transform services and observe the runtime behavior of the WCF-Custom Adapter and SqlBinding when used with either a Dynamic or Static Send Port. To this purpose, I used the Northwind database that is available on CodePlex along with the other SQL Server code samples. In particular, I created a new stored procedure called CustomersByCountry whose T-SQL code is shown below:

CustomersByCountry Stored Procedure

USE [Northwind]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

IF OBJECT_ID('CustomersByCountry') > 0 DROP PROCEDURE CustomersByCountry
GO

CREATE PROCEDURE [dbo].CustomersByCountry 
@Country nvarchar(15) = 'ALL'
AS
IF @Country = 'ALL'
SELECT [CustomerID]
      ,[CompanyName]
      ,[ContactName]
      ,[ContactTitle]
      ,[Address]
      ,[City]
      ,[Region]
      ,[PostalCode]
      ,[Country]
      ,[Phone]
      ,[Fax]
FROM [Northwind].[dbo].[Customers]
ORDER BY [CompanyName]
ELSE
SELECT [CustomerID]
      ,[CompanyName]
      ,[ContactName]
      ,[ContactTitle]
      ,[Address]
      ,[City]
      ,[Region]
      ,[PostalCode]
      ,[Country]
      ,[Phone]
      ,[Fax]
FROM [Northwind].[dbo].[Customers]
WHERE [Country] = @Country
ORDER BY [CompanyName]
GO

 

 

As you can easily note, the stored procedure returns the customers belonging to a certain country or all customers if the @Country is NULL or equal to ‘ALL’.

All the 4 test use cases of the first scenario implement the same pattern:

  • A client application sends a request message to a WCF-NetTcp Receive Location.
  • The incoming message is transformed in the format expected by the WCF-SQL Adapter and routed to a WCF-Custom Send Port. 
  • The WCF-SQL Adapter invokes the CustomersByCountry stored procedure.
  • The response message is transformed and returned back to the caller.

 

The following figure shows the map used by all the test cases of Scenario 1 to transform the response message from the native WCF-SQL format to a canonical format. I intentionally used the Uppercase, String Left Trim and String Right Trim Functoids to increase the complexity of the map.

CustomersByCountryResponseToCustomersResponse Map

OOBRoutingOOBTransform Test Case

The first test use case represents the typical flows modeled with the ESB Toolkit where the Transform and Routing services against the inbound request message are run within the On-Ramp Port. As the name of the use case suggests, all the Transform and Routing components utilized by this test are those provided out-of-the-box by the ESB Toolkit 2.0.

Itinerary

The following figure depicts the Itinerary used by the OOBRoutingOOBTransform test use case:

As mentioned above, the Transform and Routing services are both applied to the inbound message within the OnRamp Receive Location. The following picture shows how the STATIC Route Resolver used by the RouteRequest service has been configured:In particular, the Action property contains the name of the target stored procedure while the Endpoint Configuration property has been configured as follows:

BindingConfiguration=<binding name="sqlBinding" maxConnectionPoolSize="1000" useAmbientTransaction="false" />&
BindingType=sqlBinding&
IsFault=true&
PropagateFaultMessage=true&
EnableTransaction=false

 

 Architecture

The following figure depicts the architecture of the OOBRoutingOOBTransform test use case.

Message Flow
  1. A Two-Way WCF-NetTcp Receive Location receives an XML request document from Visual Studio 2008 Load Test.
  2. The ESB Itinerary Selector pipeline component running within the ItinerarySelectReceivePassthrough pipeline retrieves the OOBRoutingOOBTransform Itinerary from the EsbItineraryDb or from the in-process cache and copies it in the ItineraryHeader context property. The ESB Dispatcher pipeline component executes in sequence the standard Transform Service and Routing Service and then advances the Itinerary to the next step. In particular, the Transform Service maps the incoming message to the format expected by the WCF-SQL Adapter, and the Routing Service changes the value of the OutboundTransportLocation, OutboundTransportType and Action context properties using the data defined in the STATIC Route Resolver.
  3. The Message Agent submits the incoming message to the MessageBox (BizTalkMsgBoxDb).
  4. The message is retrieved by a Two-Way Dynamic Send Port that uses the WCF-Custom Adapter.
  5. The ESB Dispatcher pipeline component running within the ItinerarySendPassthrough pipeline retrieves the Itinerary from the ItineraryHeader context property and advances this latter to the next step.
  6. The WCF-SQL (WCF-Custom + SqlBinding) Adapter invokes the CustomersByCountry stored procedure.
  7. The WCF-SQL (WCF-Custom + SqlBinding) Adapter retrieves result data from SQL Server and prepares a response message.
  8. The ESB Itinerary Cache component running within the ItinerarySendReceivePassthrough receive pipeline  retrieves the Itinerary from the cache, and the ESB Dispatcher component executes the TransformResponse Itinerary step. This latter applies the map indicated by the STATIC Map Resolver to the response message using the standard Transform Service.
  9. The Message Agent submits the response message to the MessageBox (BizTalkMsgBoxDb).
  10. The message is retrieved by the WCF-NetTcp Receive Location that is synchronously waiting for the response document.
  11. The PassThruTransmit send pipeline is executed by the WCF-NetTcp Receive Location.
  12. The response message is finally returned to the original caller.
  Note
The ItinerarySendReceivePassthrough is a custom receive pipeline that was created as an optimization to specifically eliminate the XmlReceive component which is instead present in the ItinerarySendReceive provided out-of-the-box by the ESB Toolkit 2.0. The pipeline contains just the following components:

  • ESB Itinerary Cache
  • ESB Dispatcher

 

 

OOBRoutingCustomTransform Test Case

Compared to the first one, the second test case continues to use the default Routing Service provided out-of-the-box by the ESB Toolkit, but replaces the original Transform Service with my custom version that uses the XslCompiledTransform class.

Itinerary

The following figure depicts the Itinerary used by the OOBRoutingOOBTransform test use case:

The Transform and Routing services are both executed against the request message within the OnRamp Receive Location. In particular, the following picture shows the configuration of the TransformRequest service:

 

Architecture

The following figure depicts the architecture of the OOBRoutingCustomTransform test use case.

Message Flow
  1. A Two-Way WCF-NetTcp Receive Location receives an XML request document from Visual Studio 2008 Load Test.
  2. The ESB Itinerary Selector pipeline component running within the ItinerarySelectReceivePassthrough pipeline retrieves the OOBRoutingCustomTransform Itinerary from the EsbItineraryDb or from the in-process cache and copies it in the ItineraryHeader context property. The ESB Dispatcher pipeline component executes in sequence the custom Transform Service and the standard Routing Service and then advances the Itinerary to the next step. In particular, the Transform Service maps the incoming message to the format expected by the WCF-SQL Adapter, and the Routing Service changes the value of the OutboundTransportLocation, OutboundTransportType and Action context properties using the data defined in the STATIC Route Resolver.
  3. The Message Agent submits the incoming message to the MessageBox (BizTalkMsgBoxDb).
  4. The message is retrieved by a Two-Way Dynamic Send Port that uses the WCF-Custom Adapter.
  5. The ESB Dispatcher pipeline component running within the ItinerarySendPassthrough pipeline retrieves the Itinerary from the ItineraryHeader context property and advances this latter to the next step.
  6. The WCF-SQL (WCF-Custom + SqlBinding) Adapter invokes the CustomersByCountry stored procedure.
  7. The WCF-SQL (WCF-Custom + SqlBinding) Adapter retrieves result data from SQL Server and prepares a response message.
  8. The ESB Itinerary Cache component running within the ItinerarySendReceivePassthrough receive pipeline  retrieves the Itinerary from the cache, and the ESB Dispatcher component executes the TransformResponse Itinerary step. This latter applies the map indicated by the STATIC Map Resolver to the response message using the custom Transform Service.
  9. The Message Agent submits the response message to the MessageBox (BizTalkMsgBoxDb).
  10. The message is retrieved by the WCF-NetTcp Receive Location that is synchronously waiting for the response document.
  11. The PassThruTransmit send pipeline is executed by the WCF-NetTcp Receive Location.
  12. The response message is finally returned to the original caller.

 

CustomRoutingOOBTransform Test Case

The third test case uses my custom Routing Service along with a Two-Way WCF-Custom Static Send Port, while for mapping, it uses the original Transform Service provided out-of-the-box by the ESB Toolkit.

Itinerary

The following figure depicts the Itinerary used by the CustomRoutingOOBTransform test use case:

Note that while the TransformRequest step continues to be executed on the OnRamp Receive Location, the RouteRequest step is now executed on the OffRamp Port. However, the definition of the STATIC Route Resolver was not changed. The WCF-Custom Static Send Port used by the use case has been configured to use the sqlBinding. The following figure shows the General Tab of the WCF-Custom Adapter configuration:

Note that the Address (URI) and Action fields have not been properly configured on the Static Send Port to invoke the CustomersByCountry stored procedure on SQL Server because it’s the responsibility of the RouteRequest Itinerary step to perform this operation at runtime.

Architecture

The following figure depicts the architecture of the CustomRoutingOOBTransform test use case.

Message Flow
  1. A Two-Way WCF-NetTcp Receive Location receives an XML request document from Visual Studio 2008 Load Test.
  2. The ESB Itinerary Selector pipeline component running within the ItinerarySelectReceivePassthrough pipeline retrieves the CustomRoutingOOBTransform Itinerary from the EsbItineraryDb or from the in-process cache and copies it in the ItineraryHeader context property. The ESB Dispatcher pipeline component executes the standard Transform Service and then advances the Itinerary to the next step. In particular, the Transform Service maps the incoming message to the format expected by the WCF-SQL Adapter.
  3. The Message Agent submits the incoming message to the MessageBox (BizTalkMsgBoxDb).
  4. The message is retrieved by a Two-Way Dynamic Send Port that uses the WCF-Custom Adapter.
  5. The ESB Dispatcher pipeline component running within the ItinerarySendPassthrough pipeline retrieves the Itinerary from the ItineraryHeader context property, executes the custom RouteRequest Itinerary step and finally advances the Itinerary to the next step. In particular, the custom Routing Service changes the value of the OutboundTransportLocation and Action context properties using the data defined in the STATIC Route Resolver.
  6. The WCF-SQL (WCF-Custom + SqlBinding) Adapter invokes the CustomersByCountry stored procedure.
  7. The WCF-SQL (WCF-Custom + SqlBinding) Adapter retrieves result data from SQL Server and prepares a response message.
  8. The ESB Itinerary Cache component running within the ItinerarySendReceivePassthrough receive pipeline  retrieves the Itinerary from the cache, and the ESB Dispatcher component executes the TransformResponse Itinerary step. This latter applies the map indicated by the STATIC Map Resolver to the response message using the standard Transform Service.
  9. The Message Agent submits the response message to the MessageBox (BizTalkMsgBoxDb).
  10. The message is retrieved by the WCF-NetTcp Receive Location that is synchronously waiting for the response document.
  11. The PassThruTransmit send pipeline is executed by the WCF-NetTcp Receive Location.
  12. The response message is finally returned to the original caller.

 

 

 

 

 

 

 

 

 

CustomRoutingCustomTransform Test Case

The fourth test case uses both my custom Routing and Transform components along with a Two-Way WCF-Custom Static Send Port.

Itinerary

The following figure depicts the Itinerary used by the CustomRoutingCustomTransform test use case:

This Itinerary is identical to the one used by the CustomRoutingOOBTransform test case with the exception of the Transform service that has been replaced by my custom TransformService component.

Architecture

The following figure depicts the architecture of the CustomRoutingCustomTransform test use case.

Message Flow
  1. A Two-Way WCF-NetTcp Receive Location receives an XML request document from Visual Studio 2008 Load Test.
  2. The ESB Itinerary Selector pipeline component running within the ItinerarySelectReceivePassthrough pipeline retrieves the CustomRoutingCustomTransform Itinerary from the EsbItineraryDb or from the in-process cache and copies it in the ItineraryHeader context property. The ESB Dispatcher pipeline component executes the custom Transform Service and then advances the Itinerary to the next step. In particular, the Transform Service maps the incoming message to the format expected by the WCF-SQL Adapter.
  3. The Message Agent submits the incoming message to the MessageBox (BizTalkMsgBoxDb).
  4. The message is retrieved by a Two-Way Dynamic Send Port that uses the WCF-Custom Adapter.
  5. The ESB Dispatcher pipeline component running within the ItinerarySendPassthrough pipeline retrieves the Itinerary from the ItineraryHeader context property, executes the custom RouteRequest Itinerary step and finally advances the Itinerary to the next step. In particular, the custom Routing Service changes the value of the OutboundTransportLocation and Action context properties using the data defined in the STATIC Route Resolver.
  6. The WCF-SQL (WCF-Custom + SqlBinding) Adapter invokes the CustomersByCountry stored procedure.
  7. The WCF-SQL (WCF-Custom + SqlBinding) Adapter retrieves result data from SQL Server and prepares a response message.
  8. The ESB Itinerary Cache component running within the ItinerarySendReceivePassthrough receive pipeline  retrieves the Itinerary from the cache, and the ESB Dispatcher component executes the TransformResponse Itinerary step. This latter applies the map indicated by the STATIC Map Resolver to the response message using the custom Transform Service.
  9. The Message Agent submits the response message to the MessageBox (BizTalkMsgBoxDb).
  10. The message is retrieved by the WCF-NetTcp Receive Location that is synchronously waiting for the response document.
  11. The PassThruTransmit send pipeline is executed by the WCF-NetTcp Receive Location.
  12. The response message is finally returned to the original caller.

 

Scenario 2

The main objective of the second scenario was measuring the performance and comparing the runtime behavior of the standard message routing pattern, based on the use of Dynamic Send Ports, with the custom message routing pattern, based on the use of Static Send Ports, without message mapping. This time the target system was represented by a WCF service called CalculatorService that runs within IIS 7.5 and exposes a NetTcpBinding-based endpoint. This latter exposes a single method called Calculate which receives a request message like the one depicted in the figure below:

CalculatorRequest Message

<CalculatorRequest xmlns="http://microsoft.biztalk.cat/10/samples/esb/calculatorrequest">
  <Operations>
    <Operation>
      <Operator>+</Operator>
      <Operand1>82</Operand1>
      <Operand2>18</Operand2>
    </Operation>
    <Operation>
      <Operator>-</Operator>
      <Operand1>30</Operand1>
      <Operand2>12</Operand2>
    </Operation>
    <Operation>
      <Operator>*</Operator>
      <Operand1>25</Operand1>
      <Operand2>8</Operand2>
    </Operation>
    <Operation>
      <Operator>\</Operator>
      <Operand1>100</Operand1>
      <Operand2>25</Operand2>
    </Operation>
  </Operations>
</CalculatorRequest>

 

and returns a response message that contains the result of each operation:

CalculatorResponse Message

<CalculatorResponse xmlns="http://microsoft.biztalk.cat/10/samples/esb/calculatorresponse">
    <Results xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <Result>
            <Value>100</Value>
            <Error>None</Error>
        </Result>
        <Result>
            <Value>18</Value>
            <Error>None</Error>
        </Result>
        <Result>
            <Value>200</Value>
            <Error>None</Error>
        </Result>
        <Result>
            <Value>4</Value>
            <Error>None</Error>
        </Result>
    </Results>
</CalculatorResponse>

 

For you convenience, I’m including the code of the CalculatorService below:

CalculatorService Class

#region Copyright
//-------------------------------------------------
// Author:  Paolo Salvatori
// Email:   [email protected]
// History: 2010-06-22 Created
//-------------------------------------------------
#endregion

#region Using Directives
using System;
using System.Diagnostics;
using System.ServiceModel;
using System.Transactions;
using System.Configuration;
#endregion

namespace Microsoft.BizTalk.CAT.ESB.Services
{
    [ServiceContract(Namespace = "http://microsoft.biztalk.cat/10/samples/esb/calculatorservice")]
    public interface ICalculator
    {
        #region Contract Operations
        [OperationContract(Action = "Calculate", ReplyAction = "CalculateResponse")]
        CalculatorResponse Calculate(CalculatorRequest request); 
        #endregion
    }

    // Service class which implements the service contract.
    [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Multiple)]
    public class CalculatorService : ICalculator
    {
        #region Public Methods
        [OperationBehavior]
        public CalculatorResponse Calculate(CalculatorRequest request)
        {
            CalculatorResponse response = new CalculatorResponse();
            Operation operation = null;
            string error = null;
            double value = 0;

            try
            {
                if (request != null &&
                    request.Operations != null &&
                    request.Operations.Count > 0)
                {
                    for (int i = 0; i < request.Operations.Count; i++)
                    {
                        operation = (Operation)request.Operations[i];
                        error = "None";
                        value = 0;
                        switch (operation.Operator)
                        {
                            case "+":
                                value = operation.Operand1 + operation.Operand2;
                                break;
                            case "-":
                                value = operation.Operand1 - operation.Operand2;
                                break;
                            case "*":
                            case "x":
                                value = operation.Operand1 * operation.Operand2;
                                break;
                            case "/":
                            case "\\":
                            case ":":
                                value = operation.Operand1 / operation.Operand2;
                                break;
                            default:
                                error = string.Format("Unknown Operator: {0}", operation.Operator);
                                break;
                        }
                        response.Results.Add(new Result(value, error));
                    }
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine(string.Format("[CalculatorService] Exception: [{0}]", ex.Message));
                throw;
            }
            return response;
        }
        #endregion
    }
}

 

 

OOBRoutingNoTransform Test Case

This test case uses a simple Itinerary where the Routing Service is defined on the OnRamp Port, while a Dynamic Send Port is used to communicate with the underlying WCF service. No message transformation is carried out by this test case.

Itinerary

The following figure depicts the Itinerary used by the OOBRoutingNoTransform test use case:

The standard Routing service is  executed within the OnRamp Receive Location. No transformation is applied to either the request or response message. The following picture shows how the STATIC Route Resolver used by the RouteRequest service has been configured:

In particular, the Action property contains the Action of the target method exposed by the CalculatorService while the Endpoint Configuration property has been configured as follows:

BindingType=netTcpBinding&
BindingConfiguration=<binding name="netTcpBinding" transferMode="Buffered" maxConnections="200"><security mode="None"/></binding>&
IsFault=true&
PropagateFaultMessage=true&
EnableTransaction=false

 

  Note
Regardless if transactions are enabled and used when invoking an underlying system (SQL database or WCF service) using a WCF-Custom Dynamic Send Port and regardless the binding being used (SqlBinding, NetTcpBinding, etc.), it’s extremely important that you explicitly set the EnableTransaction property to false or true, otherwise the WCF-Custom Adapter will try to determine (checking whether the actual binding includes the TransactionFlowElement binding element), at runtime whether a System.Transactions TransactionScope was required when sending a message over a channel. For more information you can read Mustansir’s post. I run a test to measure the impact of defining or not defining the EnableTransaction property.

  • OOBRoutingNoTransform without EnableTransaction specified: 9.33 messages/sec
  • OOBRoutingNoTransform with EnableTransaction explicitly set to false: 12.00 messages/sec
Architecture

The following figure depicts the architecture of the OOBRoutingNoTransform test use case.

Message Flow
  1. A Two-Way WCF-NetTcp Receive Location receives an XML request document from Visual Studio 2008 Load Test.
  2. The ESB Itinerary Selector pipeline component running within the ItinerarySelectReceivePassthrough pipeline retrieves the OOBRoutingNoTransform Itinerary from the EsbItineraryDb or from the in-process cache and copies it in the ItineraryHeader context property. The ESB Dispatcher pipeline component executes the standard Routing Service and then advances the Itinerary to the next step. In particular, the Routing Service changes the value of the OutboundTransportLocation, OutboundTransportType and Action context properties using the data defined in the STATIC Route Resolver.
  3. The Message Agent submits the incoming message to the MessageBox (BizTalkMsgBoxDb).
  4. The message is retrieved by a Two-Way Dynamic Send Port that uses the WCF-Custom Adapter.
  5. The ESB Dispatcher pipeline component running within the ItinerarySendPassthrough pipeline retrieves the Itinerary from the ItineraryHeader context property and advances this latter to the next step.
  6. The WCF-Custom Adapter + NetTcpBinding invokes the Calculate method exposed by the CalculatorService.
  7. The WCF-Custom Adapter + NetTcpBinding retrieves result data and prepares a response message.
  8. The ESB Itinerary Cache component running within the ItinerarySendReceivePassthrough receive pipeline  retrieves the Itinerary from the cache, but the ESB Dispatcher component does not execute any services.
  9. The Message Agent submits the response message to the MessageBox (BizTalkMsgBoxDb).
  10. The message is retrieved by the WCF-NetTcp Receive Location that is synchronously waiting for the response document.
  11. The PassThruTransmit send pipeline is executed by the WCF-NetTcp Receive Location.
  12. The response message is finally returned to the original caller.

 

 

 

 

CustomRoutingNoTransform Test Case

This use case adopts my custom Routing Service along with a Two-Way WCF-Custom Static Send Port. Once again, no message transformation is carried out by this test case.

Itinerary

The following figure depicts the Itinerary used by the CustomRoutingNoTransform test use case:

With respect to the preceding test case, this time the Itinerary makes use of the custom Routing Service and the RouteRequest step is now run to the OffRamp Port. However, the definition of the STATIC Route Resolver was not changed.

Architecture

The following figure depicts the architecture of the CustomRoutingNoTransform test use case.

Message Flow
  1. A Two-Way WCF-NetTcp Receive Location receives an XML request document from Visual Studio 2008 Load Test.
  2. The ESB Itinerary Selector pipeline component running within the ItinerarySelectReceivePassthrough pipeline retrieves the CustomRoutingCustomTransform Itinerary from the EsbItineraryDb or from the in-process cache and copies it in the ItineraryHeader context property. The ESB Dispatcher pipeline component advances the Itinerary to the next step without executing any services.
  3. The Message Agent submits the incoming message to the MessageBox (BizTalkMsgBoxDb).
  4. The message is retrieved by a Two-Way Dynamic Send Port that uses the WCF-Custom Adapter.
  5. The ESB Dispatcher pipeline component running within the ItinerarySendPassthrough pipeline retrieves the Itinerary from the ItineraryHeader context property, executes the custom RouteRequest Itinerary step and finally advances the Itinerary to the next step. In particular, the custom Routing Service changes the value of the OutboundTransportLocation and Action context properties using the data defined in the STATIC Route Resolver.
  6. The WCF-Custom Adapter + NetTcpBinding invokes the Calculate method exposed by the CalculatorService.
  7. The WCF-Custom Adapter + NetTcpBinding retrieves result data and prepares a response message.
  8. The ESB Itinerary Cache component running within the ItinerarySendReceivePassthrough receive pipeline  retrieves the Itinerary from the cache, but the ESB Dispatcher component does not execute any services.
  9. The Message Agent submits the response message to the MessageBox (BizTalkMsgBoxDb).
  10. The message is retrieved by the WCF-NetTcp Receive Location that is synchronously waiting for the response document.
  11. The PassThruTransmit send pipeline is executed by the WCF-NetTcp Receive Location.
  12. The response message is finally returned to the original caller.

 

 

Scenario 3

The third scenario has been specifically created to measure and compare the performance of the standard and custom Transform Service when processing a medium-sized message (80 KB) with a map of average complexity. To this purpose, I reused the CalculatorRequest and CalculatorResponse messages that I exploited in the previous Scenario, but this time calculations are performed by the map shown in the figure below rather than by the WCF CalculatorService.

CalculatorRequestToCalculatorResponse Map

Note: The map has 4 pages, one for each possible math operation.

Then I created 2 different use cases, one using the standard Transform Service while the other uses my custom Transform Service.

SimpleRoutingSlipOOBTransform Test Case

This use case implements a one-way flow and uses a simple Itinerary where both the standard Transform and Routing Service are defined on the OnRamp Port. Therefore, at runtime, all the message processing happens within the One-Way WCF Receive location, while a One-Way Dynamic Send Port is simply used to write the response message to an output folder.

Itinerary

The following figure depicts the Itinerary used by the SimpleRoutingSlipOOBTransform test use case:

The TransformService step has been configured to use the standard Transform Service provided out-of-the-box by the ESB Toolkit, while the ROUTE Static Resolver used by the RouteMessage step has been configured to write the transformed message to a certain folder, as shown by the following picture:

Architecture

The following figure depicts the architecture of the SimpleRoutingSlipOOBTransform test use case.

Message Flow
  1. A One-Way WCF-NetTcp Receive Location receives an XML request document from Visual Studio 2008 Load Test.
  2. The ESB Itinerary Selector pipeline component running within the ItinerarySelectReceivePassthrough pipeline retrieves the SimpleRoutingSlipOOBTransform Itinerary from the EsbItineraryDb or from the in-process cache and copies it in the ItineraryHeader context property. The ESB Dispatcher pipeline component executes in sequence the standard Transform Service and the standard Routing Service and then advances the Itinerary to the next step. In particular, the standard Transform Service executes the CalculatorRequestToCalculatorResponse map to transform the inbound CalculatorRequest message into a CalculatorResponse document, and the Routing Service changes the value of the OutboundTransportLocation, OutboundTransportType and Action context properties using the data defined in the STATIC Route Resolver.
  3. The Message Agent submits the incoming message to the MessageBox (BizTalkMsgBoxDb).
  4. The message is retrieved by a One-Way Dynamic Send Port that uses the FILE Adapter.
  5. The ESB Dispatcher pipeline component running within the ItinerarySendPassthrough pipeline retrieves the Itinerary from the ItineraryHeader context property but it does not execute any services.
  6. The Send Handler of the FILE Adapter finally writes the message to the output folder indicated in the Itinerary.

SimpleRoutingSlipCustomTransform Test Case

This use case is identical to the previous one except that the original Transform Service provided out-of-the-box by the ESB Toolkit has been replaced with my custom Transform Service.

Itinerary

The following figure depicts the Itinerary used by the SimpleRoutingSlipCustomTransform test use case:

The TransformService step has been configured to use the custom Transform Service in place of the one provided out-of-the-box by the ESB Toolkit, while the ROUTE Static Resolver used by the RouteMessage step was not changed with respect to the previous use case.

  Note
If you use a Microsoft.BizTalk.CAT.ESB.Itinerary.Services.Transform custom service within an Itinerary along with a STATIC Resolver and you receive the error ‘Transport Name’ property value should not be empty or null in resolver ‘<Resolver Name>’ when you try to validate or export the Itinerary, just select (None) as Transport Location on the STATIC Resolver configuration.

Architecture

The following figure depicts the architecture of the SimpleRoutingSlipCustomTransform test use case.

Message Flow
  1. A One-Way WCF-NetTcp Receive Location receives an XML request document from Visual Studio 2008 Load Test.
  2. The ESB Itinerary Selector pipeline component running within the ItinerarySelectReceivePassthrough pipeline retrieves the SimpleRoutingSlipCustomTransform Itinerary from the EsbItineraryDb or from the in-process cache and copies it in the ItineraryHeader context property. The ESB Dispatcher pipeline component executes in sequence the custom Transform Service and the standard Routing Service and then advances the Itinerary to the next step. In particular, the custom Transform Service compiles or retrieves from the internal cache the  CalculatorRequestToCalculatorResponse map and uses it to transform the inbound CalculatorRequest message into a CalculatorResponse document, and the Routing Service changes the value of the OutboundTransportLocation, OutboundTransportType and Action context properties using the data defined in the STATIC Route Resolver.
  3. The Message Agent submits the incoming message to the MessageBox (BizTalkMsgBoxDb).
  4. The message is retrieved by a One-Way Dynamic Send Port that uses the FILE Adapter.
  5. The ESB Dispatcher pipeline component running within the ItinerarySendPassthrough pipeline retrieves the Itinerary from the ItineraryHeader context property but it does not execute any services.
  6. The Send Handler of the FILE Adapter finally writes the message to the output folder indicated in the Itinerary.

In the next episode of the series we will walk through performance tests results.  Stay tuned for Part 3!

Code

You can immediately download the code of the custom ESB services and test cases here. As always, you are kindly invited to provide feedbacks and comments.