WCF - A web service running in IIS but through a factory doesn't keep up the original exception thrown
-
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:
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)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.
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.