WCF - A web service running in IIS but through a factory doesn't keep up the original exception thrown

StackOverflow https://stackoverflow.com/questions/8732156

  •  14-04-2021
  •  | 
  •  

Question

A web service running in IIS but through a factory doesn't keep up the original exception thrown.

For example:

My web service has been marked up with FaultContractAttribute like this way:

public interface IMyService
{
    [FaultContract(typeof(MyCustomException))]
    [OperationContract]
    bool IsAuthorized();
}

My web service implementation has throws out a custom exception like this way:

public class MyService : IMyService
{
    public bool IsAuthorized()
    {
        throw new FaultException<MyCustomException>(fault, fr);
    }
}

Then:

  1. If my WCF - NOT using any factory - is similar to <%@ ServiceHost Language="C#" Debug="true" Service="MyService" %>, then on client side I CAN pick up the original exception (MyCustomException)

  2. If my WCF - USING some factory - is similar to <%@ ServiceHost Language="C#" Debug="true" Service="MyService" Factory="MyFactory" %>, then on client side I CAN'T pick up the original exception (MyCustomException) but only SOAP exception (FaultException) with useless general trace & message

Note:

WCF factory MyFactory is implemented with its SERVICE HOST contains a SERVICE BEHAVIOR initiated from IErrorHandler

In this service behavior, method ProvideFault does nothing (I haven't known how to keep up the original exception by this way)

In summary, I beg answers from expects: How to keep up the original exception (MyCustomException) while using some WCF factory ? Thanks.

Was it helpful?

Solution

In my recent project (WCF REST services) I use WebServiceHostFactory and I still was able to achieve this using IErrorHandler. Find below a sample

I created a class ExceptionInfo that could be serialized and sent back to the client.

[Serializable]
public class ExceptionInfo
{
    public string ExceptionType { get; set; }
    public string ExceptionMessage { get; set; }
    public string StackTrace { get; set; }
}

And implementing a custom error handler

[DataContract]
public class MyCustomServiceErrorHandler : IErrorHandler
{
    #region IErrorHandler Members

    /// <summary>
    /// This method will execute whenever an exception occurs in WCF method execution
    /// </summary>
    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        var exceptionInfo = new ExceptionInfo();

        if (error is MyCustomException)
            exceptionInfo.ExceptionType = error.Type.ToString();;
        else
            exceptionInfo.Type = "Unhandled Exception";

        exceptionInfo.ExceptionMessage = error.Message;            
        exceptionInfo.StackTrace = error.StackTrace;

        var faultException = new FaultException<ExceptionInfo>(exceptionInfo);

        object detail = faultException.GetType().GetProperty("Detail").GetGetMethod().Invoke(faultException, null);

        fault = Message.CreateMessage(version, "", detail, new DataContractSerializer(detail.GetType()));

        var webBodyFormatMessageProp = new WebBodyFormatMessageProperty(WebContentFormat.Xml);

        fault.Properties.Add(WebBodyFormatMessageProperty.Name, webBodyFormatMessageProp);

        var httpResponseMessageProp = new HttpResponseMessageProperty();

        httpResponseMessageProp.Headers[HttpResponseHeader.ContentType] = "application/xml";
        httpResponseMessageProp.StatusCode = HttpStatusCode.BadRequest;
        httpResponseMessageProp.StatusDescription = exceptionInfo.ExceptionMessage;

        fault.Properties.Add(HttpResponseMessageProperty.Name, httpResponseMessageProp);

    }

    /// <summary>
    /// Performs error related behavior
    /// </summary>
    /// <param name="error">Exception raised by the program</param>
    /// <returns></returns>
    public bool HandleError(Exception error)
    {
        // Returning true indicates that an action(behavior) has been taken (in ProvideFault method) on the exception thrown.
        return true;
    }

Now you can decorate your services using the above handler.

[ServiceContract]    
[ServiceErrorBehavior(typeof (MyCustomServiceErrorHandler))]
public class LoginService : ServiceBase
{}

On the client side, you can check if the HttpStatusCode of the response != Ok and deserialize the response to ExceptionInfo type and display in a message box or handle per requirement.

Hope this helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top