CIP Example: Microsoft Market

The Microsoft® Market sample site illustrates the use of a Commerce Interchange Pipeline (CIP) in an extended, practical example. Microsoft Market is a business-to-business site demonstrating internal corporate purchasing, based on Microsoft’s own internal corporate purchasing site. The application enables employees to order office supplies from their desktop using a Web browser. The result of the shopping process is the generation and transmission of a purchase order to the vendor that supplies the goods.

This section illustrates how the Market site uses a Commerce Interchange Pipeline (CIP) transmit pipeline to transmit a purchase order by HTTP.

A Pipeline Within a Pipeline

In most Commerce Server sites, the final purchase is processed by an OPP running a purchase configuration. Microsoft® Market follows the same model. In this case, the purchase configuration file is called SubmitViaInterchange.pcf, which is based on the Corporate Purchasing Submit Pipeline template.

Microsoft Market's SubmitViaInterchange pipeline

This pipeline configuration checks whether the order total requires manager approval and sends mail to the approving manager. If the order is pre-approved, it inserts the requisition in the database and executes a Commerce Interchange Pipeline (CIP) that includes stages for digitally signing and encrypting the requisition and sending it to the vendor using an HTTP post.

As the following figure illustrates, three pipelines are involved. Within the OPP, a CIP is created to perform the business-to-business transaction.

Microsoft Market's OPP and CIP pipelines

The outer pipeline executes the Scriptor component that runs TxHTTP.vbs. TxHTTP.vbs, in turn, creates and executes the Commerce Interchange Pipeline. When the Interchange pipeline completes execution, control returns to the outer pipeline. The last component of that pipeline is then executed.

Meanwhile, the purchase order is received on the vendor’s system using HTTP post. (In the sample site, for simplicity of the demonstration, GetOrder.asp is run on the same computer that is hosting Microsoft Market.)

The outer pipeline, the OPP, is created as an MtsTxPipeline object so that all operations within that pipeline are supported as a single transaction by Microsoft® Transaction Server (MTS). The inner pipeline, the Interchange, is created as an MtsPipeline object so that its components run within the same transaction created by the outer pipeline. (If the inner pipeline were created as MtsTxPipeline object, a failure of any process within it would only roll back the processes in the inner pipeline, not in the outer pipeline.)

Creating and Executing the Transmit Pipeline (Config\TxHTTP.vbs)

The Transmit pipeline is created and executed by a Scriptor component running the script TxHTTP.vbs.

The function defined in this script takes four arguments, but only the orderform argument is used in the function. This argument represents the requisition that is being transmitted to the vendor.

Assuming the requisition is pre-approved, the function begins by creating a non-transacted pipeline (mscsMtsPipeline) and loading the InterchangeTransmit.pcf pipeline configuration file. This is the Commerce Interchange Pipeline (CIP).

Next, the function creates a Transport Dictionary to be passed as an argument to the CIP. The Transport Dictionary contains a name/value pair that contains the business data object being sent (in this case, the requisition). In this function, the following phrase adds a value called Object to the Transport Dictionary, and sets this value as the requisition passed into this function:

Set TransportDictionary.object = orderform
Note

Although the Microsoft Market sample uses the name working_data to represent the business data object, the preferred standard convention is to name this value Object. Also, the name object, and not working_data, should be specified as the Object Source Key in the MapToXML component that appears in Microsoft Market’s Transmit pipeline. This documentation uses the correct convention.

The object property is used by the first component in the Interchange Transmit pipeline, MapToXML, which reads the object¸ maps the object to serialized binary form, and writes the result back into the working_data property.

Finally, the function executes the Interchange pipeline’s Execute method, passing the transport dictionary and the PipeContext dictionary as arguments.

Function mscsexecute(config, orderform, context, flags)
mscsexecute = 1
if (not orderform.needapproval) then
    Dim mscsMtsTxPipeline
    Set mscsMtsTxPipeline = CreateObject("Commerce.MtsTxPipeline")

    Dim pathPipeConfig
    REM  -- INTTRANSMIT is used , in global.asa to map the interchange pipeline to the file InterchangeTransmit.PCF.
    pathPipeConfig = context.pipemap("INTTRANSMIT")
    mscsMtsTxPipeline.loadpipe (pathPipeConfig)
    REM -- Comment here to turn logging off
    if (context.logpipeline) then
        call mscsMtsTxPipeline.setlogfile(context.approot + "\data\InterchangeTransmitPipe.log")
    end if

    REM -- create the outer dictionary which the Interchange pipeline components will use as their black-board
    Dim TransportDictionary
    Set TransportDictionary = CreateObject("Commerce.Dictionary")

   Set TransportDictionary.object = orderform

    REM -- for the auditlog
    TransportDictionary("requisitionid") = orderform.requisitionid
    TransportDictionary("insertby") = orderform.insertby
    TransportDictionary("reqemailalias") = orderform.reqemailalias

    Dim ierrorlevel
    REM -- kick off the Interchange pipeline
    On error resume next
    ierrorlevel = mscsMtsTxPipeline.execute(1, TransportDictionary,Context, 0)

    REM -- return any errors from the Interchange pipeline execution
    if (0 <> Err) then
          orderform.[_purchase_errors].Add("#:" & Err.Number & "," & Err.Description)
          mscsexecute = 3
    End if
    on error goto 0

    if (1 < iErrorlevel) and (0 = orderform.[_purchase_errors].Count) then
        orderform.[_purchase_errors].Add(replace(mscsMessageManager.GetMessage("cip_transmit_error"),"%1",ierrorlevel))
    end if
    
end if
End Function

The Transmit Pipeline Configuration

Microsoft Market’s InterchangeTransmit.pcf pipeline configuration is an example of a Commerce Interchange Transmit pipeline.

Microsoft Market's InterchangeTransmit pipeline

The pipeline begins with the requisition object passed to it in the transport dictionary, and during the course of running the pipeline, various components write new values into the transport dictionary.

The Map stage in this pipeline contains a MapToXML component, which reads the data in the business data object (using the object’s IPersistXML or IPersistStreamInit implementation), and writes the data as an XML-enclosed binary stream or as pure XML data to the working_data name/value pair.

The Digitally Sign and Encrypt stages in this pipeline are empty so that the Market sample site will work even on servers that do not have installed the certificates that these components require.

The Transport stage contains the SendHTTP component, which send the business data object as an argument to an HTTP request.

When the pipeline has completed execution, the transport dictionary is automatically destroyed (although the original order form object remains).

GetOrder.asp

Getorder.asp is the page that is run on the vendor system to receive the requisition posted by HTTP.

The TxHTTP.vbs script previously described creates a transport dictionary to pass the order form to the InterchangeTransmit pipeline. This Dictionary initially contains the order form object, and is used by other components in the CIP Transmit pipeline to write intermediate values.

Similarly, the script in GetOrder.asp creates a transport dictionary, which it passes as an argument to the pipeline. This script uses the request.form method to retrieve the information posted to the page using HTTP, and creates a name/value pair in the transport dictionary (called Text) to contain this text.

Next, this script creates a transacted pipeline (mscsMtsTxPipeline) and loads the Receive.pcf pipeline configuration.

<!-- #include file="include/shop.asp"-->
<!-- #include file="include/utility.asp"-->

<html>
<head>
    <!-- #include file="include/standardhead.asp"-->        
</head>
<body>
<% 
   REM -- receive the orderform that is posted thru HTTP.
   Dim TransportDictionary
   set TransportDictionary = server.createobject("commerce.dictionary")
   TransportDictionary.working_data = request.form
   

   Dim mscsMtsTxPipeline
   set mscsMtsTxPipeline = server.createobject("commerce.MtsTxPipeline")
   
   REM -- Get the name of the Commerce Interchange Pipeline using INTRECEIVE to key into the pipemap dictionary.
   REM -- INTRECEIVE maps to /market/config/InterchangeReceive.pcf in global.asa
   call mscsMtsTxPipeline.loadpipe(pipemap("INTRECEIVE"))

   if (logpipeline) then
        call mscsMtsTxPipeline.setlogfile(Request.ServerVariables("APPL_PHYSICAL_PATH") + "/data/InterchangeReceivePipe.log")
   end if
    
   Dim ierrorlevel,context
   set Context = server.createobject("commerce.dictionary")
   Context.DefaultConnectionString = MSCSSite.DefaultConnectionString
   Context.SiteName = MSCSSite.DisplayName
   set Context.CIP_receiveerrors = Server.CreateObject("Commerce.SimpleList")
   set Context.CIP_receiveDBerrors = Server.CreateObject("Commerce.Dictionary")
   

   on error resume next
   ierrorlevel = mscsMtsTxPipeline.execute(1, TransportDictionary, Context, 0)

   REM -- Errors are logged to the W3SVC error logs. In order for the specified string to be recorded in the log file, 
   REM -- select the URI Query option of the Extended Logging Properties sheet for the site. 

   Dim ErrNumber, ErrText, iError 
   ErrNumber = Err.Number    REM -- store the errors if any, and display if no errors raised by other pipeline components.
   ErrText = Err.description
   on error goto 0         
   
   for each iError in Context.CIP_receiveDBerrors
        Response.AppendToLog(Context.CIP_receiveDBerrors(iError))
   next

   for iError = 0 to Context.CIP_receiveerrors.Count - 1
        Response.AppendToLog(Context.CIP_receiveerrors(iError))
   next

   if (0 = Context.CIP_receiveDBerrors.count) and (0 = Context.CIP_receiveerrors.count) and (0 <> ErrNumber) then
        Response.AppendToLog("#:" & ErrNumber & "," & ErrText)
   end if

   if (1 < iErrorlevel) then
        Response.AppendToLog(E_PIPELINE_ERRORLEVEL)
   end if

%>
</body>
</html>

The Receive Pipeline Configuration

Microsoft Market’s InterchangeReceive.pcf pipeline configuration is an example of a Commerce Interchange Receive pipeline.

Microsoft Market's InterchangeReceive pipeline

Essentially, this pipeline performs the opposite actions of the Commerce Interchange Transmit pipeline, and in reverse order. Specifically, the pipeline contains the following stages and components.

The Decrypt and Verify Digital Signature stages are empty, because the object was not encrypted or digitally signed when transmitted.

In the Map stage, the MapFromXML component converts the binary stream to a Transport Dictionary, the OBJECT name/value pair of which references the business data object (an OrderForm).

In the Application Integration stage, a Scriptor component (VendorPOAccept.vbs) writes the values from the OrderForm object to the vendor’s database.


© 1997-1998 Microsoft Corporation. All rights reserved.