DomainService Error Handling

When errors occur server side in a DomainService during request processing, your customErrors configuration in web.config determines the level of error information that will be displayed to clients. By default the custom error mode is RemoteOnly. Deployed applications will likely use RemoteOnly or On to ensure that sensitive internal information and stack traces aren’t exposed.

 <system.web>
    <customErrors defaultRedirect="GenericError.htm" mode="RemoteOnly">
       <error statusCode="500" redirect="InternalError.htm"/>
    </customErrors>
 </system.web>

RIA Services respects this configuration when sending error information back to the client. However, while clients are getting “sanitized” error info, on the server you’ll likely want to do very detailed error logging of unhandled exceptions. For example, on the server you have full exception stack traces and context on the operation in progress (e.g. User, ChangeSet being processed, etc.), all of which can be written to the log to aid in application debugging. In previous releases there wasn’t a centralized place to do this – if you wanted to consolidate that logic, you had to override each of the three virtual DomainService Query/Submit/Invoke operations and wrap the call to base with exception handling. For example here’s a Query override:

    1: public override IEnumerable Query(QueryDescription queryDescription, 
    2:     out IEnumerable<ValidationResult> validationErrors, out int totalCount)
    3: {
    4:     IEnumerable results = null;
    5:     validationErrors = null;
    6:     totalCount = -1;
    7:  
    8:     try
    9:     {
   10:         results = base.Query(queryDescription, out validationErrors, out totalCount);
   11:     }
   12:     catch(Exception e)
   13:     {
   14:         this.LogError(e);
   15:     }
   16:  
   17:     return results;
   18: }
   19:  
   20: private void LogError(Exception e)
   21: {
   22:     // ServiceContext provides information on the operation
   23:     // being processed, current User, etc.
   24:     DomainServiceContext sc = this.ServiceContext;
   25:  
   26:     // Custom logging logic, e.g. log to a local file
   27:     // error database, etc.
   28: }

In the latest release we’ve addressed this by adding a virtual OnError method that the framework will call whenever an unhandled exception occurs. This provides a centralized place to process all unhandled exceptions:

    1: protected override void OnError(DomainServiceErrorInfo errorInfo)
    2: {
    3:     base.OnError(errorInfo);
    4:  
    5:     this.LogError(errorInfo.Error);
    6: }

The reason the parameter is the Type DomainServiceErrorInfo and not the exception itself is because we wanted to allow for the possibility of error transformation – allowing you to inspect the exception and specify a different exception to propagate back to the client. Expect to see that functionality in the next release :)