Processing and Retrieving Messages and Exceptions from the Fault Message
Having published the Fault message with the two persisted messages (ApprovedRequest and DeniedRequest) and a persisted Exception object from the EAIProcess orchestration, we'll move forward and demonstrate how to extract the messages and the Exception objects in secondary orchestration schedules.
There is really only one method for extracting an Exception object: the GetException()
API. However, there are two methods for extracting messages. One
provides a typeless method to retrieve all messages persisted to the
Fault message. The other provides a strongly-typed approach.
Typeless Message Retrieval
The typeless approach is
useful if you have a general logging need, or you don't have access to
the schema assembly used in the originating orchestration that persisted
the messages. In this case, a collection of messages can be returned
using MoveNext() to enumerate through them.
This allows
developers to inspect the message context properties and do whatever
they want with them, e.g., process them, send them out to a SharePoint
site, etc. For example, a generic orchestration exception process may do
the following:
Retrieve array of messages from Fault message.
Inspect context properties to determine message type or retrieve other context values.
Based on message type or other criteria, look up processing instructions via Business Rule Engine.
Process individual messages per business rule evaluation.
This makes for an
extremely decoupled exception processing solution. The EAIGenericHandler
orchestration, located in the BootCamp.Orchestration.Exception.
FaultHandler project, is a good example demonstrating the typeless
approach and is shown in Figure 6-23. In this example, the orchestration is configured as follows:
The
Receive shape is configured with a filter expression:
("Msft.Samples.BizTalk. Exception.Schemas.FaultCode" == "1001"). This
effectively subscribes the orchestration to any Fault messages published
where the FaultCode equals 1001.
The Receive shape is bound to a direct bound receive port.
The Expression shape directly below the Receive shape has the following code snippet that calls the GetMessages() API:
msgs = Msft.Samples.BizTalk.Exception.ExceptionMgmt.GetMessages(FaultMsg);
The msgs variable
is declared of type MessageCollection. This returns an array of
messages, including their original context properties, from the Fault
message.
A Loop shape is configured to call
msgs.MoveNext()
Within the Loop shape, an Expression shape is configured to retrieve the current message in the collection by calling
TmpMsg = msgs.Current;
TmpMsg is a message variable declared as a System.Xml.XmlDocument.
Each message in the collection is then published to a direct bound port.
A physical send port is configured to serialize each message to a folder.
NOTE
Message Construct
shapes are not necessary within the example. The API for the exception
handler takes care of constructing new messages within the BizTalk
runtime.
When this orchestration
executes, it will retrieve all the messages from the Fault message
(i.e., ApprovedRequest and DeniedRequest) and serialize them to disk via
the send port subscription.
Strongly-Typed Message Retrieval
Another effective
approach is retrieving the messages from the Fault message as
stronglytyped messages. This is done by referencing the schema
assemblies used by the originating orchestration.
The
EAIProcessHandler orchestration, located in the BootCamp.Orchestration.
Exception.FaultHandler project, is a good example demonstrating the
strongly-typed approach. The orchestration flow is shown in Figure 12.
In this example, the orchestration is configured as follows:
The
Receive shape is configured with a filter expression:
("Msft.Samples.BizTalk. Exception.Schemas.FaultCode" == "1001"). This
effectively subscribes the orchestration to any Fault messages published
where the FaultCode equals 1001.
The Receive shape is bound to a direct bound receive port.
The Expression shape directly below the Receive shape has the following code snippet, which calls the GetMessage() and GetException() APIs:
//Retrieve the two original messages from the Fault message
RequestMsg = Msft.Samples.BizTalk.Exception.ExceptionMgmt.GetMessage(FaultMsg,
"ApprovedRequest");
DeniedMsg = Msft.Samples.BizTalk.Exception.ExceptionMgmt.GetMessage(FaultMsg,
"DeniedRequest");
//Retrieve the System.Exception from the original service
newExc = Msft.Samples.BizTalk.Exception.ExceptionMgmt.GetException(FaultMsg);
// Write the error value to event log (need admin rights)
System.Diagnostics.EventLog.WriteEntry _
("EAIProcessHandler",newExc.Message.ToString());
Both RequestMsg and DeniedMsg are strongly typed using the schemas in the originating orchestration.
newExc is declared as a variable of type System.Exception.
If repair is needed:
RequestMsg is sent to the folder drop via a port.
An InfoPath processing instruction is added to it to facilitate editing as shown in Figure 13.
The
InfoPath form is designed to submit repaired data to a BizTalk HTTP
receive location configured under the receive port for the EAIProcess
orchestration.
DeniedMsg is published to a direct bound port.
A physical send port is configured to serialize the message to a folder.
If repair is not needed:
Each message is then published to a direct bound port.
A physical send port is configured to serialize each message to a folder.
NOTE
Message Construct
shapes are not necessary within the example. The API for the exception
handler takes care of constructing new messages within the BizTalk
runtime.
The form in Figure 13
is configured to use a BizTalk HTTP receive location URL as its submit
data source. Once submitted, it will activate a new instance of the
EAIProcess orchestration.
When this orchestration
executes, it will retrieve all the messages from the Fault message
(i.e., ApprovedRequest and DeniedRequest) and set them into
strongly-typed message variables. In fact, if you stop the send port
subscriptions and run the orchestration, you can see the original
context property values on the messages; the context properties were set
from the originating orchestration (see Figure 14).
NOTE
In Figure 14, the ReceivedFileName
property that was set before the originating orchestration processed
the message and threw the exception. Also, the API persists all custom Promoted properties as noted by the Qty property. This is an incredibly handy feature to have.
Beyond the Next Horizon
As can be seen
from the previous sections, the Failed Orchestration Routing API is
powerful enough to allow developers to handle orchestration-generated
exceptions. With a little work and a good design, you can handle
orchestration exceptions the same way you would handle messaging
subsystem exceptions using the Failed Message Routing feature of BizTalk
Server 2006.
The samples provided online,
specifically the EAIGenericHandler and EAIProcessHandler
orchestrations, demonstrate simple patterns for accessing both the
exception messages as well as the state from the original processing
orchestration. This state, in the form of the original messages, can be
accessed as strongly-typed or typeless XLANG messages.
Standardize
how application exceptions are detected and caught in the BizTalk
environment, i.e., messaging and orchestration subsystems.
Provide common patterns that allow automated processes to react and manage application exceptions.
Provide a loosely coupled exception management pattern that facilitates reuse.
If you take this
pattern a step further and extend the API, you could provide another
method that creates canonical Fault messages generated either by the
Failed Message Routing feature of BizTalk Server 2006 or the Failed
Orchestration Routing API. A generic, BizTalk Group—wide send port could
be configured to subscribe to all Fault messages, regardless of source,
call the method, and then post all canonical Fault messages to a
central web-based portal. That would satisfy the last design goal:
The final step would be to
dynamically generate business intelligence data from the Fault messages
going through the BizTalk environment. That's right; you call that BAM
in BizTalk Server 2006.
Remember the following scenario we described earlier and the solution walkthrough we proposed:
A user
submits an invoice to the system. During the course of processing the
invoice within an orchestration, the Business Rule Engine throws an
application exception because some piece of the data is incorrect. The
business process should catch the exception, send the offending message
to another person or system that can correct the message, and resubmit
the message for processing.
To implement the use case, we envisioned a sequence of events would need to happen, as presented earlier in the subsection "BizTalk Server 2006 Failed Message Routing As a Blueprint" and repeated here for your convenience:
A developer is assigned responsibility for the recently deployed Financial Reporting BizTalk application.
A
new exception message arrives in the SharePoint-based exception
management portal indicating a data integrity issue with an
orchestration in the Financial Reporting BizTalk application.
The
developer is notified of the new exception either through his
subscription to the SharePoint application list or because the exception
exceeded a threshold predefined in BAM.
The
developer navigates to the SharePoint-based exception management portal
and examines the Fault message posted as well as the individual
orchestration messages and their context properties that were persisted.
The
developer determines that this will be a common error that will require
manual intervention and correction by the Finance team and resubmission
to the system.
The
developer creates and deploys an independent BizTalk orchestration
project that subscribes to the specific exception and application
information.
The
project is designed to retrieve the invalid message from the Fault
message, send the message to the Finance team for correction, and
correlate the corrected message back to orchestration and resubmit.
A
week later the developer navigates to the SharePoint-based exception
management portal to view that the application exception trends for
invalid messages have decreased dramatically since the deployment of his
solution.
If you extend the
Failed Orchestration Routing API, you could make the solution
walkthrough a reality with very little effort. This need is not unique
to a specific BizTalk application; it tends to be ubiquitous in BizTalk
environments to provide operational visibility into the health of the
applications deployed. This becomes a vital function in Enterprise
Service Bus (ESB) type deployments.
In the upcoming release
of the Microsoft ESB Toolkit, this API will be extended to accommodate
the scenarios we described previously. This should prove invaluable for
anyone deploying applications in the future.