You are on page 1of 8

WCF Developers Guide Error Handling

A number of standardized components encompassing Oracle user-defined types, .Net Libraries,


javascript/JQuery, and the Microsoft Enterprise Library (MS EL) has been developed and configured to
provide for standardized error handling and notification for WCF Services @ Kemi.
The purpose of this document is to provide an overview of these components, and how they should be
employed in WCF Interface and Library projects.
Handling Exceptions in a WCF Service
Lets start with a code-snippet from one of our WCF Services and examine the components of the code
sample.

Example:
Try
_ds = OracleHelper.ExecuteDataset(_cmdText, _cmdParms)
oraCmnHldr = CType(OracleHelper.GetParmValue(_cmdParms, "av_cmmn_hldr"), _
Oracle.DataAccess.Types.OracleString)
If ErrorHandling.ServiceFault.f_noFaultFound(_svcFault, oraCmnHldr) Then
myOutput.Add(OracleHelper.GetParmValue(_cmdParms, "ar_ptcp_key"))
myOutput.Add(OracleHelper.GetParmValue(_cmdParms, "at_participants"))
Else
Throw New Exception(oraCmnHldr)
End If

Catch ex As DBException
If IsNothing(_svcFault) Then
_svcFault = New ErrorHandling.ServiceFault("Unexpected Error - Contact Help Desk")
_svcFault.ThrowKIWIException(Of DBException)(ex)
End If

Catch ex As DbParameterException
If IsNothing(_svcFault) Then
_svcFault = New ErrorHandling.ServiceFault("Invalid Parameter(s)", "SVC Error")
End If
_svcFault.ThrowKIWIException(Of DbParameterException)(ex)

Catch ex As Exception
If IsNothing(_svcFault) Then
_svcFault = New ErrorHandling.ServiceFault()
End If
Dim _tmp As String = "Unexpected error retrieving Participant List. Contact help desk."
_svcFault.ThrowKIWIException(Of Exception)(New Exception(_tmp, ex)

Finally

End Try
B
C
D
E
F
A
Oracle Helper Library (A)
The OracleHelper class is defined in the /common/Kemi.DataAccess project within the wcf
solution. A detailed description of this class along with its public methods and properties is
provided in a separate document - insert document name here.
The functions in the OracleHelper methods contain code to detect database connectivity errors.
When a connectivity exception is detected, the following tasks are performed:
1) Email notification(s) generated via Microsoft Enterprise Library
2) New DBException is thrown

Checking for an Error Condition in Oracle Procedure (B)
A standard convention of our Oracle procedures is to return error/warning messages in a
parameter named av_cmmn_hldr. If av_cmmn_hldr contains a value upon return from Oracle
procedure, we need to check the value to determine is an error condition has been encountered
that requires an exception to be thrown.
The ServiceFaultClass contains the method f_noFaultFound which will check the value returned
in the av_cmmn_hldr parameter to determine if a fault condition exists. The method has two
overloads, and will return a value of true if no fault conditions are detected.
In addition to av_cmmn_hldr, a list of messages (T_MSG_TBL) can be returned from an Oracle
procedure. This provides a means of notifying the service consumer of multiple conditions with
a single fault, instead of requiring multiple service calls/faults to notify the consumer of multiple
conditions. The method OracleHelper.msgListParameter("at_msgs") has been included in
the Kemi.DataAcess library to facilitate the creation of this parameter.

Public Shared Function f_noFaultFound(
ByRef svcfault As ErrorHandling.ServiceFault, _
ByVal cmmnHldr As Oracle.DataAccess.Types.OracleString, _
Optional ByVal msglist As Kemi.Exceptions.T_MSG_TBL = Nothing) As Boolean

Public Shared Function f_noFaultFound(
ByRef svcfault As ErrorHandling.ServiceFault, _
ByVal cmmnHldr As String, _
Optional ByVal msglist As Kemi.Exceptions.T_MSG_TBL = Nothing) As Boolean

True cmmnHldr is empty or contains NO DATA FOUND and msglist is empty
False cmmHldr not in (,NO DATA FOUND) OR msglist contains at least one message
with a FaultSeverity of Authentication or above.

G
Handling a DBException (C)
Critical exceptions occur when there is an error in connecting to the database. The standard
connection functionality (OracleHelper.* in Kemi.DataAccess.dll) will detect and report these
critical error, after which it will throw a new DBException which should be handled in your code.

- You must use the functionality provided by OracleHelper in order to take advantage of this
critical error handling. In addition to standard connection functionality, the OracleHelper
class has been enhanced to provide standard methods for creating oracle parameters and
handling errors/exceptions that arise when the parameters are being created.

- When handling a DBException in your code, you should always pass the DBException to the
ThrowKIWIException method of the ServiceFault (described in detail below). Based on this
exception type, the ThrowKIWIException method will skip attempting to log a database
connection in the database. You should not throw an exception of this type from within your
own code.
DBParameter Exception (D)
The DBParameterException is defined in /common/Kemi.Exceptions, and thrown from the
OracleHelper Parameter functions described in Insert document name here. You should not
throw an exception of this type from within your own code.
This exception typically indicates that the value supplied for a parameter is not valid. For
example, calling OracleHelper.DateParameter with a string value that does not contain a valid
date would result in a DBParameter Exception.

ServiceFault (E, F)
The ServiceFault class - defined in the common/Kemi.WCF project defines the data that is
returned to the caller when a service method returns without completing normally. In the
typical KEMI implementation, this fault data is returned to a javascript/JQuery client where it is
used to display error information for the user (described in more detail later in this document).
Public Properties
Name Description
_faultCodes List of valid types that can be used in T_MSG_TBL.
"IMSADWREC"
Description A string containing a brief description of the exception. The
description should not contain any technical details, but rather a
user-friendly message such as Document Not Available, User not
authorized to view document, etc.
PolicyName Name of Microsoft Enterprise Library Exception Handling policy.
FaultSeverity The severity of the fault condition. The values for FaultSeverity
correspond to the each position in _faultCodes. See the table below.
FaultType [replaced by FaultSeverity] maintained for backward compatability.
MsgList List of error/warning messages
FaultSeverity Codes
Code FaultSeverity MS Ent Library Policy Name
I Information
(information / warning that
does not require processing to
be halted)

M RIM
(agreement in RIM status)

S Restricted
(database in restricted mode)

A Authentication
(user authentication error)
SVC Authentication
D DataValidation
(data validation errors)
SVC DataValidation
W Warning
(warning the requires
processing to be halted)
SVC Warning
R ImageRight
(error occurred in ImageRight)
SVC ImageRight
E Error SVC Error
C Critical Error
(database connection errors)
SVC Critical

Methods
Public Sub New(ByVal faultMessage As String, _
ByVal _msgList As Kemi.Exceptions.T_MSG_TBL)

- Description = faultMessage
- FaultSeverity = calculated based on content of _msglist
- PolicyName derived from FaultSeverity SVC + FaultSeverity
- MsgList populated with contents of _msgList


Calculating Fault Severity
The FaultSeverity is based on the contents of _msgList.
Condition Calculation
_msgList is Empty FaultSeverity is set to Critical (highest available value)
_msgList is Not Empty _msgList is scanned to identify the highest level
_faultCode for any single message in the list. Once the
max _faultCode is identified, the FaultSeverity is set to
the corresponding value (see table above).

If _msgList contains an item with an undefined
_faultCode, the FaultSeverity will be set to crtical.
Public Sub ThrowKIWIException(Of T As Exception)(ByVal _ex As T)

Once a ServiceFault has been populated, this method is called to perform the following tasks:
Handling an Exception in the Context of a Service Call
Log the Exception WEB2_DBA.WCFActivity
Report the Error Microsoft Enterprise Library (Exception Handling, Logging)
Notify Service Consumer ServiceFault Exception

Code Snippet


Line # Description
213 If a DBException (connectivity) error occurred, do not write to log.
217 DBException throw exception with ServiceUnavailable status
220 Use _ex.Message as the Description
222 Get MS Enterprise Library Policy Name. The FaultSeverity is
calculated as a part of this process.
223 Log the Exception
226 Report The Error utilizes MS Enterprise Library to generate email
notifications
228 Notify Service Consumer - Generate WebFaultException (REST) or
FaultException (SOAP)

Kemi.Exceptions (G)
This contains the definitions for DBExpcetion and DBParameter Exception (described earlier in this
document), as well as the following classes which allow for an array of messages/warnings to be passed
from on Oracle procedure to the consumer of the service.
- Public Class KIWI_MSG
o Generated from the oracle user-defined type kiwi_msg
CREATE OR REPLACE TYPE "KIWI_MSG" AS object (
typ char(1) -- defined by ServiceFault
, cde number -- any numeric value
, text varchar2(200)) -- warning/message text

- Public Class KIWI_MSG_TBL
o Generated from the oracle user-defined type kiwi_msg_tbl
CREATE OR REPLACE TYPE "KIWI_MSG_TBL" AS TABLE OF WEB2_DBA.KIWI_MSG

o This user-defined type was originally used to return a list of messages from oracle
procedure/function to the vb.net service library. While the type and corresponding vb.net
class are maintained for backward compatibility, the T_MSG_TBL type/class are prefrerred.

- Public Class T_MSG_TBL
o Generated from the oracle user-defined type
CREATE OR REPLACE TYPE t_msg_tbl AS OBJECT (
messages kiwi_msg_tbl,
msgCount number,
CONSTRUCTOR FUNCTION t_msg_tbl RETURN SELF AS RESULT,
MEMBER PROCEDURE append(typ VARCHAR2, cde NUMBER, txt VARCHAR2),
MEMBER PROCEDURE append(kmsg kiwi_msg))

o This user-defined type is utilized within oracle procedures/functions to compile a list of
error/warning conditions that should be reported to the consumer of the service.

o The append functions defined in the type specification above have been implemented to
add another message to the list and update the value of the msgCount property.

o When a ServiceFault is created with an instance of this class, the content of the messages
property is used to calculate the severity of the error/warning. In turn, the calculated
severity will be used to determine how the warning/error conditions should be logged and
reported to both IT and the consumer of the service.
Implementing Exception Handling in your WCF Service
- Required Libraries
o Kemi.DataAccess Standard DB Connection and Parameter processing.
o Kemi.Exceptions Defines custom exceptions and T_MSG_TBL class.
o Kemi.WCF Defines ServiceFault class and associated methods

- Standards to follow
o Create database connection/parameters via Kemi.DataAccess.OracleHelper

o Use ServiceFault.f_notFaultFind to determine if an exception should be thrown after
returning from an Oracle procedure.

o Catch Exceptions as described in the example at the beginning of this document
You can use the generic Catch ex As Exception by itself. This will result in
all exceptions being handled in the same fashion.
The advantage provided by handling individual Exceptions is the opportunity
to perform unique processing based on the specified type of exception.
If choose to catch multiple types of exceptions, the Catch ex As
Exception must appear as the last catch-clause in the try-catch block.

- Including custom information in Error Notification Emails
o A custom formatter has been implemented to include additional information such
as the service endpoint, parameters, username, etc. in the error notification emails
that are generated via the enterprise library.

o The custom information is included via wcfLogToken extensions to the current
OperationContext. If extensions of the type wcfLogToken are present in the
operation context when the custom email formatter is invoked, the extensions will
be removed from the OperationContext, and the data they contain will be included
at the beginning of the email, prior to the standard stack trace and exception
information generated via the Enterprise Library.
o wcfLogToken is defined Kemi.Exceptions and contains a list of label/value pair.

o Your custom error information must be added to the operation context prior to
executing the ThowKiwiException method on the ServiceFault.

o Example:
Dim _wcfLogToken As wcfLogToken = New wcfLogToken()
Dim _token As New wcfLogToken_Record("Label 1","Custom Data 1")
_wcfLogToken.logToken.Add(_token)
System.ServiceModel.OperationContext.Current.Extensions.Add(_wcfLogToken)


Handling Service Errors in JavaScript
- The common scripts effects\kemi.global.js and effects\kemi.kiwi.js have been implemented to
provide a standard interface for invoking WCF Methods and handling the initial return from the
WF Service Call. Two of the parameters supplied to the jsCallService function are:
-
o aSuccess callback routine in local script when WCF Method exists normally
o aError callback routine in local script when WCF Method exists with a fault

- The jsCallService function performs initial handling for faults, before returning control to the
callback routine specified in aError.

o If the fault returned from the WCF Method is an authorization error, a timeout, an
unknown error, or an Oracle error, the user is redirected to the standard error page
within the web application.
o Otherwise, control is returned to the local error handling routine specified by aError.

- The following is an example of a local error handling routine for WCF Faults:
function jsDocServiceFailure(request, status, error) {
//display error messages returned from the wcf service
_excpList = new Array();
if (request.responseText.substr(0, 14) == '{"Description"') {
_wcfFault = JSON.parse(request.responseText);
_wcfFaultMsg = "";
if (_wcfFault.MsgCount > 0) {
for (ix = 0; ix < _wcfFault.MsgCount; ix++) {
_wcfFaultMsg += _wcfFault.MsgList[ix].msgText + "<br>";
}
}
else
_wcfFaultMsg = _wcfFault.Description;
if (_wcfFault.FaultType.toUpperCase().indexOf("ERROR") > 0)
jsAlert(_wcfFaultMsg, null, 400, null, null, null);
}
else {
jsAlert("Unable to contact server");
}
jsEndRequestJs();
}