Exception Handling in QBO 3

posted May 15, 2012, 2:26 PM by Eric Patrick   [ updated Jul 6, 2016, 8:26 PM ]


Error handling in DEV, UAT and PROD environments should be done differently. QBO 3 has several optional web.config settings to address error handling:

SettingDEV/UAT PRODComments
qbo.Application.Properties.Settings / HttpErrorsDetailedBriefBrief: only one-line error messages are returned
Detailed: a full stack trace is returned
Default: Brief
qbo.Application.Properties.Settings /   HttpErrorTransformError.Detailed.xsltError.Select.xsltIf detailed errors are rendered, this setting determines the XSLT to use to render the errors.
Default: Template/Application/Error.Select.xslt 
exceptionHandlingPolicySee belowSee below Leverages the Microsoft ETL Exception Handling Block. This is extremely configurable.

For production systems, end users should never, ever, ever see a stack trace. It reveals enough information about the system to arm hackers with enough knowledge to attempt hacking the system.

For DEV systems (typically local machines), full stack traces are very useful during the development cycle.

For UAT systems, early testing may justify detailed errors, while later testing justifies shorter error messages (for limited client testing).


Error handling in QBO 3 leverages the Microsoft Enterprise Template Library's Exception Handling block, enabling web.config-driven:
  • Logging of all errors to logging sinks (text file, database, Amazon Simple DB, email, etc.)
  • Logging of specific types of errors to different logging sinks (e.g. SQL deadlocks get emailed to DBAs)
  • Suppression of some types of errors (e.g. poorly configured Score errors can be logged, but not raised to the user)
  • Masking of some types of errors as other errors
Controlling what happens with a specific error depends on the exception class raised. For example, we can target different logging sinks based on:
  • System.Exception
  • qbo.Exception.GeneralException
  • qbo.Exception.ConfigurationException
  • qbo.Exception.ListenerException
  • etc.
For developers, as you code exception handling into your methods, choose carefully the type of exception you raise. Your choice will control how the exception handling can be configured. For example, if you choose to always raise a qbo.Exception.GeneralException, this will always be handled with other qbo.Exception.GeneralException errors, and cannot be targeted to a specific logging sink or suppressed.  On the other hand, if you are writing a pluging for a Method Listener, you should choose to raise a qbo.Exception.ListenerException, so that all "plugin" errors can be logged to a plugin-specific log.

You are welcome to create new Exception classes (typically derived from qbo.Exception.AbstractException) if you feel you have a category of errors that may need to be handled specially.

On top of the exception handling block, the qbo.Application.HttpHandler will trap all errors raised from derived ashx pages, and render them via Templates/Application/Error.Select.xslt. This XSLT can be customized to mask error messages as well, and currently renders haiku because I was bored during some conference calls. 

Use Case: Suppress Listener Errors

During unit testing on my local machine, I sometimes want to test my code while ignoring errors related to plugins. Specifically, the standard ImportForm.config file includes Method Listeners to invoke qbo2.EventHandler so custom forms can process decisions. I often don't care about processing decisions, so I have two options:
  1. Modify ImportForm.config, commenting out the relevant method listeners, or
  2. Modify web.config, suppressing any qbo.Exception.ListenerException errors raised
In order to test the exception handling, and to avoid changing ImportForm.config in source (as I am constantly re-deploying the DecisionWeb project), I elected for option 2. My web.config file was modified to:

<add name="StandardPolicy">
<!-- This is standard -->
<add name="All Exceptions" type="System.Exception, mscorlib, ..." postHandlingAction="NotifyRethrow">
<add name="Logging Exception Handler" logCategory="General" type="..." eventId="100" severity="Error" title="Enterprise Library Exception Handling" formatterType="..." priority="0"/>

<!-- This is my custom handler for ListenerExceptions -->
<add name="Listener Exception" type="qbo.Exception.ListenerException, qbo.Exception" postHandlingAction="None">
<add name="Logging Exception Handler" type="..." logCategory="General" eventId="100" severity="Error" title="Enterprise Library Exception Handling" formatterType="..." priority="0"/>

  • The second entry handles qbo.Exception.ListenerException errors, and has a postHandlingAction="None"
  • I've replaced some long type string with ... for readability; you can see the full entry in source > ... > qbo.ApplicationWeb > web.config

RESTful Error Codes

The qbo.Exception module includes custom exceptions, and an IException interface.  The IException interface allows a developer to specify a recommended HttpStatusCode when raising an exception. For example:

throw new Exception.DataException("You don't have access") { StatusCode = (int)HttpStatusCode.Forbidden };

will raise an exception, and cause HttpHandler to set the Context.Response.StatusCode to Forbidden (403).

As you code plugins or extend QBO3, ensure client-caused exceptions throw a 4xx errors.  Server-caused exceptions should throw 5xx errors. See also RESTful-friendly errors.

IIS Masking all Errors as 500 - A Server Error Occurred

Error messages are controlled via /Templates/Application/Error.Select.xslt.

If IIS is only serving up 500 - A Server Error Occurred, do the following:
  • In IIS Manager > {WebSite} > Features View, double-click on Error Pages
  • Right-click on the 500 status code, and choose Edit Feature Settings
  • Under Error Responses, choose "Detailed Errors"
  • Click Okay

Thanks to: