Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

enter image description here

But in the end, it always return this:

enter image description here

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.

like image 409
fiberOptics Avatar asked May 29 '12 10:05

fiberOptics


1 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
}
like image 107
L.B Avatar answered Nov 14 '22 05:11

L.B