Reputation: 1305
I am pretty new to WCF in general. What little experience I have comes from using fairly simple .SVC services in ASP.NET web applications.
I tried experimenting with using a WCF Project for the first time, and ran into a major show-stopper.
As I’m sure most are aware, for some strange reason, in a web application in which the customErrors mode is set to On
<customErrors mode = “On” />
services (both .ASMX and .SVC) will not return exception details to the client. Instead, the exception and stack trace are emptied, and the message always reads “There was an error processing the request”, which is not at all helpful.
When services are directly hosted inside the web application itself, it’s easy to work around this restriction by placing the services in a dedicated folder, and setting customErrors to "Off" for that folder.
However, I’m running into this same issue with exceptions not being returned from services that live in a separate WCF project. Thing is, I don’t know how to work around that.
In a nutshell: I need to get my WCF Project services to bubble REAL exceptions to the client – or at least, the original exception message, instead of “There was an error processing the request”.
EDIT: I should probably point out here that the reason I'd like to return exceptions is that I'm often calling these services from the client side via Ajax (jQuery), and would like to format the return message differently if it's a "normal" return (like say, use green text), and then use red text if it's an error. I handle the message formatting in the $.ajax object's error handler, which obviously will only run when the service fails.
I should also point out that everything works fine with customErrors Off:
<customErrors mode = “Off” />
So, I'm thinking maybe there's some configuration property that can be set to stop the ASP.NET runtime from killing my exception when using customErrors.
Here is some related info I found on this.
Upvotes: 4
Views: 3385
Reputation: 1531
You could look at implementing the IErrorHandler interface to capture any exceptions and return a FaultException that is specified by your contract.
Upvotes: 1
Reputation: 58622
You have another option to catch the exceptions you want to bubble to the client, and return service faults.
There is a little more design work that has to go on because you have to design the Fault Contracts themselves, but it gives you the flexiblity to return whatever you want to the client. So you could design a contract that details the error, and stack trace if you deem nessessary.
Example:
[DataContract(Namespace = "urn:// or http://....")]
public class ClientNeedsToKnowFault
{
[DataMember]
public List<Error> Errors
{
get { return _errors; }
set { _errors = value; }
}
....
public ClientNeedsToKnowFault() { }
public ClientNeedsToKnowFault(string message)
{
Message = message;
Errors = new List<Error>() { new Error(message) };
}
...
//Helper method to throw
public static void ThrowFault(string message, List<Error> errorList)
{
throw new FaultException<ClientNeedsToKnowFault>(new ClientNeedsToKnowFault(message, errorList));
}
Once you design your faults you add an additional attribute to a service method.
[FaultContract(typeof(ClientNeedsToKnowFault))]
void MyServiceMethod();
And the last step would be to throw it. As you can see above i just put a helper method to throw it because i think the FaultException process is a little messy.
I will say that the major con of this approach is having to catch the Fault on the client side. But if the information is important enough to return a fault, you probably want this complexity.
Upvotes: 3
Reputation: 47809
The real answer here is that you should probably always avoid bubbling real exceptions to the caller. The "ServiceResponse" pattern is a useful one here. The idea is that you will return a "ServiceResponse" class that contains whatever response values your service needs, but also has some sort of "IsError" flag in addition to a property that lets you return an Exception object.
Then, the service can simply handle all errors and return that information:
public ServiceResponse MyService()
{
try {
// ... do work here
return new ServiceResponse { WhateverReturnValue = true };
} catch(Exception e) {
return new ServiceResponse { IsError = true, Error = e };
}
}
Upvotes: 1