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 :)
Comments
Anonymous
May 29, 2010
Thanks, this is very useful. I was just trying to do some error transformation and then ran accross this. Looking forward to that feature! GregAnonymous
August 16, 2010
Thanks for the post. I seem to get a useless stack trace for any errors that occur though. What could be the problem? at System.Web.DomainServices.ReflectionDomainServiceDescriptionProvider.ReflectionDomainOperationEntry.Invoke(DomainService domainService, Object[] parameters) at System.Web.DomainServices.DomainOperationEntry.Invoke(DomainService domainService, Object[] parameters, Int32& totalCount) at System.Web.DomainServices.DomainService.Query(QueryDescription queryDescription, IEnumerable`1& validationErrors, Int32& totalCount)Anonymous
August 18, 2010
Hmm, what is the exception message? For exceptions thrown from user methods, you should get the correct stack trace including the domain operation. I just tested this out and thats what I see.Anonymous
August 23, 2010
The comment has been removedAnonymous
August 24, 2010
The framework unwraps TargetInvocationExceptions so you should be getting the right stack trace. I've not heard anyone complain of this issue before. If you email me a repro I could take a look.Anonymous
August 25, 2010
Hi I've put together an example project at dl.dropbox.com/.../DomainServiceErrorHandling.zip ThanksAnonymous
August 25, 2010
I see the issue - I assumed initially that you were on the .NET 4.0 RTM bits. You're using the pre RTM .NET 3.5 PDC drop. You're likely running into a bug that has subsequently been fixed in the RTM bits. So unless you move to the RTM version, I'm afraid you won't be able to get around this.Anonymous
August 25, 2010
Thanks Matthew. Unfortunately we haven't yet upgraded to VS 2010, so will have to use the PDC beta. As a workaround I'm going to add try... catch to every method which will call a private method to log the exception.Anonymous
August 26, 2010
As a workaround I've done a similar solution to your pre-OnError method code, but also added logic to pass the exception back to the Silverlight client when debugging or when certain types of exception occur. forums.silverlight.net/.../462107.aspxAnonymous
November 08, 2010
Hi. How do i meke the error transformation in the protected override void OnError(DomainServiceErrorInfo errorInfo) 2: { 3: base.OnError(errorInfo); 4: 5: this.LogError(errorInfo.Error); 6: } thanks in advanceAnonymous
November 08, 2010
Juan - to "transform" the error, you can inspect the exception information in errorInfo.Error and set a completely new exception (errorInfo.Error = myError).Anonymous
November 08, 2010
Thanks for the fast reply. Could you make a brief example? ie. i´m trying to catch a sql exception and show a descriptive message to the client. i needs to know how to catch by type.(in this case a sqlException) and in the client, how to print, in the on error in the domainservice i have: protected override void OnError(DomainServiceErrorInfo errorInfo) { BLLException be = new BLLException("Here should put a message", errorInfo.Error.InnerException); } in the client: private void observacionDomainDataSource_LoadedData(object sender, LoadedDataEventArgs e) { if (e.HasError) { System.Windows.MessageBox.Show(e.Error.Message.ToString(), "Error en la carga", System.Windows.MessageBoxButton.OK); e.MarkErrorAsHandled(); } } thanks in advanceAnonymous
May 26, 2011
Great post… now I understand type moment. Works in SL4 WCF RIA as advertised.