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