none
Failed Message Routing without Orchestration - Accessing ErrorReport properties

    Question

  • Hello,

    I have a BizTalk solution that has multiple send/receive ports but no orchestration. I would like to use Failed Message Routing to log any exceptions that may occur.

    I'm using the following filter on a send port to subscribe to the failed messages

    ErrorReport.ErrorType == FailedMessage
    

    However, when the send port forwards the message to a FILE, I can only see failed message's content.

    I would like to access the error related properties of Failed Message Routing i.e. I would like to access the following properties that are associated with the failed message

    • ErrorReport.ProcessingServer
    • ErrorReport.SendPortName
    • ErrorReport.ReceivePortName
    • ErrorReport.FailureTime
    • ErrorReport.Description

    When I look at the Routing Failure Report, I can see all the values that I need. I just need to access these values and assemble an exception log entry be sent to an in house Exception Logging service.

     

    In the end I would like to have a message that will have the following info

     <FailureTime></FailureTime>
     <ProcessingServer></ProcessingServer>
     <SendPortName></SendPortName>
     <ReceivePortName></ReceivePortName>
     <Description></Description>
     <message>
       <!-- Failed message content -->
     </message>
    

    How can I do this?

     

    Thanks in advance,

    Alper

     

     

     

    Wednesday, February 16, 2011 8:33 PM

Answers

  • You need to create a new message containing the ErrorReport properties as elements in the message.
    Use an orchestration to subscribe to the FailedMessages.
    1. Use a map to create the new message be sure to create empty elements for the error properties
    2. Use message assignment to populate the ErrorReport elements from the incoming message context. You can use promoted properties or distinguished fields on your new message or just use the xpath function to do this.

    • Marked as answer by ASUNAR Thursday, February 17, 2011 4:59 PM
    Wednesday, February 16, 2011 9:16 PM
    Answerer
  • If you do not want to use an Orchestration to access the message context properties then you can do this in a custom pipeline.

    You can either get it to attach a second message part to create a "meta data" file, or wrap up the message body with a wrapper document with your extra elements in it.

    • Marked as answer by ASUNAR Thursday, February 17, 2011 4:59 PM
    Thursday, February 17, 2011 10:54 AM

All replies

  • You need to create a new message containing the ErrorReport properties as elements in the message.
    Use an orchestration to subscribe to the FailedMessages.
    1. Use a map to create the new message be sure to create empty elements for the error properties
    2. Use message assignment to populate the ErrorReport elements from the incoming message context. You can use promoted properties or distinguished fields on your new message or just use the xpath function to do this.

    • Marked as answer by ASUNAR Thursday, February 17, 2011 4:59 PM
    Wednesday, February 16, 2011 9:16 PM
    Answerer
  • If you do not want to use an Orchestration to access the message context properties then you can do this in a custom pipeline.

    You can either get it to attach a second message part to create a "meta data" file, or wrap up the message body with a wrapper document with your extra elements in it.

    • Marked as answer by ASUNAR Thursday, February 17, 2011 4:59 PM
    Thursday, February 17, 2011 10:54 AM
  • Hi Alper,

    I understand you want a message only solution not involving service instance.

    Access message properties in custom pipeline and use them in Send port's Outbound Mapper : In your case you want "FailureTime","SendPortName", "SendPortName" in your output message. These will be available in the errored message as promoted properties since you have enabled "Generate error report for failed messages". If you want these properties as an value of element in the output message, create a custom pipeline where you can access the context properties of the message. And use a send port mapper ("Outbound map") to mapper the values from the input message (errored message) to the output message (message as you have shown above).

    To Access Failed message content into the output message : While defining the schema for the output message Under"<message>", create a "<Any> element node" (rightclick on message element -->Insert Schema Node -->"Any Element". And inside the mapper call a c# helper component write code similar to

    public static XMLDocument (xmlDocument inputErrorMsg)

    {
    //Constrct output message
    //XMldocumet and and the following
     string xmlMsg = inputErrorMsg.OuterXml;
     xmlMsg = inputErrorMsg.OuterXml;
    //Add formatted xmlMsg into the XMLDocument
    //retrun XMlDocument
    }


    Cheers
    M.R.ASHWINPRABHU

    If this answers your question please mark it accordingly

     

     

    Thursday, February 17, 2011 11:23 AM
  • A outbound map on a send port will only be executed if the message's Message Type matches the input schema type of the map. As the error report has no Message Type, the map will not be run.

    The only option for a messaging only solution is to use a custom pipeline component to modify the outbound message as Alastair suggests.

    Thursday, February 17, 2011 11:53 AM
    Answerer
  • Thanks for taking the time to answer my questions. I would like to provide more context to ask for suggestions.
    Here is the workflow of the BizTalk solution
    1. Receive Location/Port from GetUnprocessedCustomers stored procedure: Poll SQL Server 2008 with WCF-SQL adapter by calling stored proc that returns (WHERE IsProcessed = 0)
    2. SendPort to 3rd Party web service: Filtered to ReceivePortName == <ReceivePort name mentioned above> with an outbound map to convert message returned from the above mentioned stored proc to service schema
    3. SendPort to UpdateIsProcessed stored proc: Filtered to MessageType == <message type returned from service> with an outbound map to convert service response to stored procedure call that will update IsProcessed = 1

    This setup is working. What I would like to do is to handle any exceptions that may occur in this process and send that information to an internal exception handling service. Some of the possible exceptions are

    1. ReceiveLocation cannot access database, stored proc does not exist or insufficient execute rights.
    2. 3rd part service is not accessible.
    3. SendPort cannot access database, stored proc does not exist or insufficient execute rights.

    I would like to achieve this with the most unobtrusive manner possible. My limited experience with BizTalk makes adding an orchestration or a custom pipeline a significant effort. I'm also considering the following option.

    1. Enable failed message routing on the ReceivePort from GetUnprocessedCustomers stored proc.
    2. Create a SendPort
            - URI: <url of the internal exception handling service>
            - Outbound Map: A map that will create a message for the internal exception handling service with hardcoded values
            - Filter: ErrorReport.ReceivePortName == <receive port name in step 1>
    3. Enable failed message routing on the SendPort to 3rd Party service.
    4. Create a SendPort
            - URI: <url of the internal exception handling service>
            - Outbound Map: A map that will create a message for the internal exception handling service with hardcoded values
            - Filter: ErrorReport.SendPortName == <send port name in step 3>

    This is definitely not an ideal solution as I need to repeat these steps for every send/receive port in my solution.

    I tend to favor adding an orchestration over a custom pipeline because the CustomPipeline component sample that comes BizTalk is not very simple.


    Thoughts, suggestions? How do you handle exceptions in your BizTalk solutions?



    • Edited by ASUNAR Thursday, February 17, 2011 6:54 PM typo
    Thursday, February 17, 2011 6:53 PM
  • I have decided to bite the bullet and create an orchestration for exception handling.

    I have created the following schema to hold ErrorReport properties I'm interested in. For simplicity, I am not gonna worry about the original message.

    ....

     

     <xs:complexType>
     <xs:sequence>
     <xs:element name="FailureCode" type="xs:string" />
     <xs:element name="FailureTime" type="xs:string" />
     <xs:element name="MessageType" type="xs:string" />
     <xs:element name="ProcessingServer" type="xs:string" />
     <xs:element name="ReceivePortName" type="xs:string" />
     <xs:element name="SendPortName" type="xs:string" />
     </xs:sequence>
     </xs:complexType>
    

     

    ....

    Made all the fields distinguished so that I can access them from the orchestration.

    "1. Use a map to create the new message be sure to create empty elements for the error properties"

    I'm not sure how to do this. I know that the destination schema will be the schema I mentioned above. However, I don't know what the source schema should be.

    I would like to subscribe to all failed messages and access the ErrorReport properties. Therefore, depending on the type of the failed message I think the schema may be different. 

    Do I

     

    • create a generic schema with an element of xs:any type as the source schema of my map? 
    • create a map to map all available message types to my destination schema ? (please say no :)
    The other question I have is about the entry point to the orchestration. I think I will set the filter on the receive shape to ErrorReport.ErrorType == "FailedMessage".
    How should the ReceivePort that will be connected to the ReceiveShape be configured?

    How can I receive the FailedMessages? Should the receive location type be FILE, WCF-SQL, WCF-BasicHttp? None of them makes sense to me.

    Thanks in advance.

     

    • Edited by ASUNAR Thursday, February 17, 2011 11:01 PM formatting
    Thursday, February 17, 2011 10:21 PM
  • If you do not need to copy the message content, you do not need a map.
    Start with a Receive shape, a Construct Message shape with a MessageAssignment shape and a send shape.
    Add a message called InputMessage of type System.Xml.XmlDocument.
    Add a message called OutputMessage using your schema defined above.
    Add a one-way receive port (If you want to receive all Failed messages then set port type to "Direct" otherwise "Specify Later"
    Connect receive port to receive shape and set receive shape Activate = true
    Set filter on Receive shape of ErrorReport.ErrorType == "FailedMessage"
    Add a Variable called xmlDocVariable of type System.Xml.XmlDocument
    Add this code to the MessageAssignment shape.

    xmlDocVariable.Load("<xml of your message including empty nodes for all distinguished fields>");
    OutputMessage = xmlDocVariable;
    OutputMessage.FailureCode = InputMessage(ErrorReport.FailureCode);
    OutputMessage.FailureTime = InputMessage(ErrorReport.FailureTime);
    etc...

    Specify OutputMessage on the Send shape
    Connect send shape to send port

    Friday, February 18, 2011 9:43 AM
    Answerer
  • Thanks for the instructions Greg. This works great. I just replaced xmlDocVariable.Load(..) with xmlDocVariable.LoadXML(...) as the former method does not accept string parameter. 

    I tested the orchestration by setting the uri of the service to an incorrect value. I was able to capture the ErrorReport properties of the failed message successfully.

    However, when I

    • changed the database name to an incorrect value in the WCF-SQL adapter binding in the ReceiveLocation or
    • changed the stored proc name to an incorrect value in the WCF-SQL adapter binding in the ReceiveLocation
    I'm unable to catch these kinds of exceptions and they go straight to the Event Log. This makes sense because the error message says something like: The Messaging Engine failed to create the ReceiveLocation etc. There is no failed message to speak of.

    My question is:
    How can I create a catch all exception handler that will capture exception like the ones I tested for above? Do I need to create another orchestration with a scope and associated exception handler (type:System.Exception)? I could not figure out which shape I need to put in the scope.

     

    Thanks again for your patience.

    Friday, February 18, 2011 10:43 PM
  • Please, see a good article by Mr.Restrepo http://winterdom.com/2005/08/smtpadapterinbts2006andhtmlformattedmessages 
    It has a code how to consume the properties from the ErrorReport and pack it together with failed message.

    If you use ErrorReport properties like FailedMessage(ErrorReport.ReceivePortName)
    enslose it to the if statement as: 

    if (ErrorReport.ReceivePortName exixts FailedMessage)
    { var_portName = FailedMessage(ErrorReport.ReceivePortName);}

    otherwise if the FailedMessage came from the SendPort and didn't get this property, you get the run-time error.


    Leonid Ganeline [BizTalk MVP] BizTalkien: Suspend shape and Convoy
    Saturday, February 19, 2011 6:06 AM
    Moderator
  • Hi Leonid,

    I am able to consume the ErrorReport properties following Greg's instructions above. However, I would like to catch other types of exceptions (not just failed messages) as well.

     

    How can I create a generic solution that will capture all exceptions and send exception info (such as exception datetime, message, stack trace etc.) to an internal service?

     

    Thanks for your time.

    Monday, February 21, 2011 3:20 PM