views:

231

answers:

3

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: http://bit.ly/9tlmCO

+1  A: 

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 };
  }
}
Joel Martinez
I have seen this pattern used alot, we generalize it a little more and have a Value Object, and Error List and then derive HasError based on the list not being null and having something in it.
Nix
Yeah, there's a lot of variations on it, but the root concept is that you should return a consistent value regardless of whether there was an internal fault. The client should only have to handle things like end point not found (ie. config issue on their end)
Joel Martinez
This seems like a valid approach. The only issue here is that, as far as the client is concerned, the service will always return a "good" response, which makes it difficult to format the returned message differently for error conditions. (See my EDIT in the original post)
MissingLinq
Oh no, not a good approach. Next you'll be returning Error Numbers.
Khalid Abuhakmeh
Bad advice IMHO. Faults exist in SOAP as a first class citizen for a reason. You shouldn't leak all exceptions out as faults, but you should be using faults to report logical exceptions.
Drew Marsh
+1  A: 

You could look at implementing the IErrorHandler interface to capture any exceptions and return a FaultException that is specified by your contract.

MattK
This is a very bad idea, you don't want to throw exceptions from your service (use faults) and generally you don't want to expose the stack trace of your exceptions to the end user (security).
Nix
Good point...commencing edit to remove reference to IncludeExceptionDetailInFaults property ;)
MattK
that's a much better recommendation that your first one was!
marc_s
+2  A: 

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.

Nix
I actually tried this, but still, when <customErrors mode="On" />, the exception message (actually, the entire exception object and the stack trace) is supressed.With <customErrors mode="Off"/>, everything works fine. Which leads me to believe that somehow, I have to sneak the exception past the ASP.NET runtime somehow. ;)
MissingLinq
you need to catch the exception on server side , as well as regenerate your proxy. if you need me to add that to the post i can.
Nix
I am catching the exception. But as I said, all I'm getting is the message "“There was an error processing the request”. Not sure what you mean by "regenerating the proxy" -- maybe that's what I'm missing...
MissingLinq
By the way, in this example, is "Error" also a custom class?
MissingLinq
yes sorry, i should have said that. My error class is 3 properties message, category, priority.
Nix
+1 FaultContracts are the way to go
Shiraz Bhaiji
Okay, I am a little closer now. I got this working on the server side, but I cannot for love or money get the message back on the client when calling the service via Ajax from the client side.PLUS, another twist -- when I call from the client side, the throwing of the FaultException doesn't immediately return... the service just keeps going like nothing happened. WTF?
MissingLinq
Okay, I have been catching the exception on the client side, meaning the "consumer" side, I should say. I think I need to catch it in the service. Wow, confusing.
MissingLinq
Its a little confusing at first, but once you get it it is all down hill from there.
Nix