How to Handle WebFaultException to return CustomException?

I made my custom exception that will be thrown inside try-catch each time an error is occured:

[Serializable]
public class CustomException : Exception
{
    public CustomException() { }

    public CustomException(string message)
        : base(message) { }

    public CustomException(string message, Exception innerException)
        : base(message, innerException) { }
}  

I have two services, REST and SOAP. For SOAP services, I don't have any problem on throwing my custom exception. But in REST, I encountered a lot of difficulties.

Here is the method for throwing a WebFaultException:

    public static WebFaultException RestGetFault(ServiceFaultTypes fault)
    {
        ServiceFault serviceFault = new ServiceFault();
        serviceFault.Code = (int)fault;
        serviceFault.Description = ConfigAndResourceComponent.GetResourceString(fault.ToString());
        FaultCode faultCode = new FaultCode(fault.ToString());
        FaultReasonText faultReasonText = new FaultReasonText(serviceFault.Description);
        FaultReason faultReason = new FaultReason(faultReasonText);
        WebFaultException<ServiceFault> webfaultException = new WebFaultException<ServiceFault>(serviceFault, HttpStatusCode.InternalServerError);

        throw webfaultException;
    }  

ServiceFault is a class where it has some properties which I use to put all information I need.

I use this method to throw an exception inside REST service:

    public static CustomException GetFault(ServiceFaultTypes fault)
    {
        string message = fault.ToString();
        CustomException cusExcp = new CustomException(message, new Exception(message));
        throw cusExcp;
    }  

A sample REST Service (log in method):

    [WebInvoke(UriTemplate = "Login", Method = "POST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
    public Session Login(ClientCredentials client, LogCredentials loginfo)
    {
        try
        {
            // Login process
            return copied;
        }
        catch (LogicClass.CustomException ex)
        {
            LogicClass.RestGetFault(LogicClass.EnumComponent.GetServiceFaultTypes(ex.Message));
            throw ex;
        }
    }  

The MVC part:

Controller:

    [HttpPost]
    public ActionResult Login(LoginCredentials loginfo)
    {
        try
        {
            string param = "{"client":" + JSonHelper.Serialize<ClientAuthentication>(new ClientAuthentication() { SessionID = Singleton.ClientSessionID })
                           + ", "loginfo":" + JSonHelper.Serialize<LoginCredentials>(loginfo) + "}";

            string jsonresult = ServiceCaller.Invoke(Utility.ConstructRestURL("Authenticate/Login"), param, "POST", "application/json");
            UserSessionDTO response = JSonHelper.Deserialize<UserSessionDTO>(jsonresult);

        }
        catch (Exception ex)
        {
            return Json(new
            {
                status = ex.Message,
                url = string.Empty
            });
        }

        return Json(new
        {
            status = "AUTHENTICATED",
            url = string.IsNullOrWhiteSpace(loginfo.r) ? Url.Action("Index", "Home") : loginfo.r
        });
    }  

I use ServiceCaller.Invoke to call REST API and retrieve the response: ServiceCaller.cs

public class ServiceCaller
{
    public static string Invoke(string url, string parameters, string method, string contentType)
    {
        string results = string.Empty;
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(url));
        request.Method = method;
        request.ContentType = contentType;

        if (!string.IsNullOrEmpty(parameters))
        {
            byte[] byteArray = Encoding.UTF8.GetBytes(parameters);
            request.ContentLength = byteArray.Length;
            Stream dataStream = request.GetRequestStream();
            dataStream.Write(byteArray, 0, byteArray.Length);
            dataStream.Close();
        }

        try
        {
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            if (HttpStatusCode.OK == response.StatusCode)
            {
                Stream responseStream = response.GetResponseStream();
                int length = (int)response.ContentLength;

                const int bufSizeMax = 65536;
                const int bufSizeMin = 8192;
                int bufSize = bufSizeMin;

                if (length > bufSize) bufSize = length > bufSizeMax ? bufSizeMax : length;

                byte[] buf = new byte[bufSize];
                StringBuilder sb = new StringBuilder(bufSize);

                while ((length = responseStream.Read(buf, 0, buf.Length)) != 0)
                    sb.Append(Encoding.UTF8.GetString(buf, 0, length));

                results = sb.ToString();
            }
            else
            {
                results = "Failed Response : " + response.StatusCode;
            }
        }
        catch (Exception exception)
        {
            throw exception;
        }

        return results;
    }
}  

I am expecting the REST service to return this on client side:

在这里输入图像描述

But in the end, it always return this:

在这里输入图像描述

What should I do? Please help.

EDIT

Here is the sample response when calling the soap service:

[FaultException: InvalidLogin]
   System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) +9441823  

Did you see the "InvalidLogin" ? That is what I want to see on the response from REST servivce.
Sample response from REST:

[WebException: The remote server returned an error: (500) Internal Server Error.]
   System.Net.HttpWebRequest.GetResponse() +6115971  

I throw a WebFaultException but I receive a WebException .
If I won't be able to fetch the exact error message on REST, I will go for SOAP.
Thanks for the answers.


When using HttpWebRequest (or a Javascript client), your custom exception has no meaning for them. Just Http error codes(like 500 Internal server error) and the data in the response's content.

So you have to handle the exception by yourself. For example, if you catch WebException you can read the content(the error message) in Xml or Json format depending on your server configurations.

catch (WebException ex)
{
    var error = new StreamReader(ex.Response.GetResponseStream()).ReadToEnd();
    //Parse your error string & do something
}

I just had similar issue few minutes back. Maybe it helps. I was trying to use an extension for all my service calls like below:

Here is the BAD piece of code:

public static void ExecuteServiceMethod(this IMyRESTService svc, Action svcMethod)
{ 
    try
    {
       // try to get first last error here
       string lastError = svc.CommHandler.CH_TryGetLastError();
       if (!String.IsNullOrEmpty(lastError))
          throw new WebFaultException<string>(lastError, System.Net.HttpStatusCode.InternalServerError);

       // execute service method
       svcMethod();
    }
    catch (CommHandlerException ex)
    {
       // we use for now only 'InternalServerError'
       if (ex.InnerException != null)
           throw new WebFaultException<string>(ex.InnerException.Message, System.Net.HttpStatusCode.InternalServerError);
       else
           throw new WebFaultException<string>(ex.Message, System.Net.HttpStatusCode.InternalServerError);
     }
     catch (Exception ex)
     {
        throw new WebFaultException<string>(ex.Message, System.Net.HttpStatusCode.InternalServerError);
     }
}

Here is the FIXED piece of code:

public static void ExecuteServiceMethod(this IMyRESTService svc, Action svcMethod)
{
    // try to get first last error here
    string lastError = svc.CommHandler.CH_TryGetLastError();
    if (!String.IsNullOrEmpty(lastError))
       throw new WebFaultException<string>(lastError, System.Net.HttpStatusCode.InternalServerError);

    try
    {
       // execute service method
       svcMethod();
    }
    catch (CommHandlerException ex)
    {
       // we use for now only 'InternalServerError'
       if (ex.InnerException != null)
           throw new WebFaultException<string>(ex.InnerException.Message, System.Net.HttpStatusCode.InternalServerError);
       else
           throw new WebFaultException<string>(ex.Message, System.Net.HttpStatusCode.InternalServerError);
     }
     catch (Exception ex)
     {
        throw new WebFaultException<string>(ex.Message, System.Net.HttpStatusCode.InternalServerError);
     }
}

So... Probably you noticed that the very first throw , is handled into the catch (Exception ex) block which throws again, making it to display always: 'Internal Server Error ' . Maybe it helps, because I see you have also a global

catch (Exception exception) { throw exception; }

which might be the cause of it.


1) Add faultcontract to method/operation

2) Throw WebFaultException or WebFaultException

3) On Client side catch into webexception and then read the exception response

catch (WebException exception)
{
var resp = new StreamReader(exception.Response.GetResponseStream()).ReadToEnd();
}

Same issue faced as mentioned in the problem statement and able to resolve with the answer mentioned by LB and followed few other posts. So summing up the steps followed

链接地址: http://www.djcxy.com/p/60096.html

上一篇: 从.com重定向到.org

下一篇: 如何处理WebFaultException以返回CustomException?