2012-05-29 71 views
7

我提出,將try-catch代碼裏面每一個錯誤發生時被拋出我的自定義異常:如何處理WebFaultException以返回CustomException?

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

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

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

我有兩個服務,REST和SOAP。對於SOAP服務,我在拋出自定義異常時沒有任何問題。 但是在REST中,我遇到了很多困難。

這裏是拋出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是一個類,其中有一些屬性,我用它來把我需要的所有信息。

我使用此方法來拋REST服務內的異常:

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

樣品REST服務(登錄方法):

[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; 
     } 
    } 

的MVC部分:

控制器:

[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 
     }); 
    } 

我用ServiceCaller.Invoke調用REST API和檢索響應: 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; 
    } 
} 

我期待的REST服務,在客戶端返回此:

enter image description here

但在最後,它總是返回此:

enter image description here

我該怎麼做?請幫忙。

編輯

這裏是調用SOAP服務時的示例響應:

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

你看到 「InvalidLogin」?這就是我想看到的來自REST servivce的響應。從REST
樣本響應:

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

我拋出一個WebFaultException,但我收到WebException
如果我無法在REST上獲取確切的錯誤消息,我會去使用SOAP。
感謝您的答案。

+0

沒有答案?嗯... :( – fiberOptics

+0

這是一個WCF服務,如果是這樣,你的配置設置爲返回錯誤到客戶端? – Slick86

+0

我正在尋找相同類型的答案...我似乎無法弄清楚如何使一個REST像處理程序拋出一個有意義的異常我基本上必須處理我的JavaScript使用textStatus作爲通過或失敗 – farina

回答

4

使用HttpWebRequest(或Javascript客戶端)時,您的自定義異常對它們沒有任何意義。只是Http錯誤代碼(如500內部服務器錯誤)和響應內容中的數據。

所以你必須自己處理異常。例如,如果您抓到WebException,則可以使用Xml或Json格式讀取內容(錯誤消息),具體取決於您的服務器配置。

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

我已經這樣做了,但我想看到的是我自己的錯誤消息。有沒有反正覆蓋HTTP錯誤代碼?或異常消息?在肥皂服務工作正常,但不是在REST。謝謝。 – fiberOptics

+0

@ user72213如果您閱讀回覆,您應該看到您的自定義消息。(可能在一些XML form)用這個消息拋出一個自定義的異常是你應該在客戶端處理的東西,如果你用純HttpWebClient實現了基於soap的客戶端,你也會遇到同樣的問題。 –

0

我剛剛在幾分鐘前就有過類似的問題。也許它有幫助。我試圖使用延長像下面我所有的服務電話:

這裏是BAD一段代碼:

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); 
    } 
} 

這裏是固定一段代碼:

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); 
    } 
} 

所以......可能你注意到,第一個throw,被處理成catch (Exception ex)塊,它再次拋出,使其始終顯示:'內部服務器錯誤'。也許它有幫助,因爲我看到你也有一個全球的

趕上(例外例外){拋出異常; }

這可能是它的原因。

0

1)faultcontract到方法/操作

2)拋出WebFaultException或WebFaultException

3)添加在客戶端捕捉到引發WebException然後讀取異常響應

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

同樣的問題面臨正如問題陳述中提到的那樣,並且能夠用LB提及的答案來解決,並遵循其他幾個帖子。所以總結了以下步驟