1. Open the BalloonShop Web Application in a browser.
2. Log in as a customer you’ve previously created, add some products to your cart, and place an order.
3. Check your inbox for new mail. An example of this is shown in Figure 14-4.
8213592a117456a340854d18cee57603
Figure 14-4. Email from PSDummy
4. Examine the Audit table in the database to see the new entries. An example is shown in Figure 14-5 (note that the dates are in dd/mm/yyyy format in this figure).
Figure 14-5. Audit table entries from PSDummy
How It Works: Basic Order Processing
The main body of the OrderProcessor class is the Process method, which is called by the Checkout.aspx (and will be called later by the order admin pages) to process an order. The order to be processed is set by the constructor of OrderProcessor as noted earlier and is indicated either by an ID or a CommerceLibOrderInfo object.
The first thing that Process does is set ContinueNow to true and log the start of its execution in the Audit table:
public void Process() {
// configure processor ContinueNow = true;
// log start of execution
CreateAudit("Order Processor started.", 10000);
C H A P T E R 1 4 ■ O R D E R P I P E L I N E 533
■Note 10000 is the message number to store for the audit entry—we’ll look at these codes in more detail in a little while.
Next we come to the order processing itself. The model used here checks the Boolean ContinueNow field before processing a pipeline section. This allows sections to specify either that processing should continue when they’re finished with the current task (by setting ContinueNow to true) or that processing should pause (by setting ContinueNow to false). This is necessary because you need to wait for external input at certain points along the pipeline, such as checking whether stock is available.
The pipeline section to process is selected by the private GetCurrentPipelineSection method, which eventually selects a section based on the status of the order, but currently just has the job of setting the Current➥
PipelineSection field to an instance of PSDummy:
private void GetCurrentPipelineSection() {
// select pipeline section to execute based on order status // for now just provide a dummy
CurrentPipelineSection = new PSDummy();
}
Back to Process, you see this method being called in a try block:
// process pipeline section try
{
while (ContinueNow) {
ContinueNow = false;
GetCurrentPipelineSection();
Note that ContinueNow is set to false in the while loop—the default behavior is to stop after each pipeline section.
After you have a pipeline section, you need to process it. All sections support the simple IPipelineSection interface, defined as follows:
public interface IPipelineSection {
void Process(OrderProcessor processor);
}
All pipeline sections use a Process method to perform their work, and this method requires an OrderProcessor reference because the pipeline sections need access to the order and customer details exposed by the order processor.
The last part of the while loop (and try block) in OrderProcessor calls this method:
CurrentPipelineSection.Process(this);
} }
This calls the Process method in PSDummy, which we’ll come back to shortly.
The last part of the Process method in OrderProcessor involves catching exceptions, which might be OrderProcessorException instances or other exception types. In either case, you send an email to the administrator using the MailAdmin method (we’ll cover this in a little while), add an audit entry, and throw a new OrderProcessorException that can be caught by users of the OrderProcessor class:
catch (OrderProcessorException ex) {
MailAdmin("Order Processing error occurred.", ex.Message, ex.SourceStage);
CreateAudit("Order Processing error occurred.", 10002);
throw new OrderProcessorException(
"Error occurred, order aborted. "
+ "Details mailed to administrator.", 100);
}
catch (Exception ex) {
MailAdmin("Order Processing error occurred.", ex.Message, 100);
CreateAudit("Order Processing error occurred.", 10002);
throw new OrderProcessorException(
"Unknown error, order aborted. "
+ "Details mailed to administrator.", 100);
}
Regardless of whether processing is successful, you add a final audit entry saying that the processing has completed.
finally {
CommerceLibAccess.CreateAudit(Order.OrderID, "Order Processor finished.", 10001);
} }
At this point, it’s worth examining the message number scheme chosen for order-processing audits. In all cases, the audit message number is a five-digit number. The first digit of this number is either 1 if an audit is being added by OrderProcessor, or 2 if the audit is added by a pipeline section. The next two digits are used for the pipeline stage that added the audit (which maps directly to the status of the order when the audit was added). The final two digits uniquely identify the message within this scope. For example, so far you’ve seen the following message numbers:
• 10000: Order processor started.
• 10001: Order processor finished.
• 10002: Order processor error occurred.
Later you’ll see a lot of these that start with 2, as you get on to pipeline sections, and include the necessary infor- mation for identifying the pipeline section as noted previously. We hope you’ll agree that this scheme allows for plenty of flexibility, although you can, of course, use whatever numbers you see fit. As a final note, numbers ending in 00 and 01 are used for starting and finishing messages for both the order processor and pipeline stages, whereas 02 and above are for other messages. There is no real reason for this apart from consistency between the components.
C H A P T E R 1 4 ■ O R D E R P I P E L I N E 535
The PSDummy class that is used in this skeleton processor performs some basic functions to check that things are working correctly:
public class PSDummy : IPipelineSection {
public void Process(OrderProcessor processor) {
processor.CreateAudit("PSDoNothing started.", 99999);
processor.CreateAudit("Customer: "
+ processor.Order.Customer.UserName, 99999);
processor.CreateAudit("First item in order: "
+ processor.Order.OrderDetails[0].ItemAsString, 99999);
processor.MailAdmin("Test.", "Test mail from PSDummy.", 99999);
processor.CreateAudit("PSDoNothing finished.", 99999);
} }
The code here uses the AddAudit and .MailAdmin methods of OrderProcessor to generate something to show that the code has executed correctly. Note that the numbering schemes outlined previously aren’t used there, as this isn’t a real pipeline section.
That was a lot of code to get through, but it did have the effect of making the client code very simple:
// Process order
OrderProcessor processor = new OrderProcessor(orderId);
processor.Process();
Short of setting all the configuration details in web.config, there is very little to do because OrderProcessor does a lot of work for you. It’s worth noting that the code you have at this point is for the most part a consequence of the design choices made earlier. This is an excellent example of how a strong design can lead straight to powerful and robust code.