在這裡我主要考慮在Web環境下異常的處理, 根據HTTP協議的定義, 每次請求都會返回一個 HTTP Status Code , 不同的Code代表了不同的意義。因此我們的Web應用程序也應該是這樣,根據不同的結果返回不同的 HTTP Status Code , 比如200,代表服務端正確的返回,417代表我們期望的服務端異常,404,請求不存在等, 以及301我們的未授權。
在WCF環境下,我們首先要給每個方法添加 FaultContract, 如下:
FaultContract(typeof(WebFaultException<WebErrorDetail>))
其次我們要對異常做一些處理,讓服務端能返回正確的HTTP Status Code.
復制代碼 代碼如下:
try
{
//BussinessCode.....
}
catch (DuplicateException ex)
{
throw new WebFaultJsonFormatException<WebErrorDetail>(new WebErrorDetail(ex.Message, ex), HttpStatusCode.ExpectationFailed);
}
catch (NotExistException ex)
{
throw new WebFaultJsonFormatException<WebErrorDetail>(new WebErrorDetail(ex.Message, ex), HttpStatusCode.ExpectationFailed);
}
catch (AppException ex)
{
throw new WebFaultJsonFormatException<WebErrorDetail>(new WebErrorDetail(ex.Message, ex), HttpStatusCode.ExpectationFailed);
}
catch (Exception ex)
{
throw new WebFaultJsonFormatException<WebErrorDetail>(new WebErrorDetail(ex.Message, ex), HttpStatusCode.ExpectationFailed);
}
其中WebFaultJsonFormatException的簽名如下:
[Serializable, DataContract]
public class WebFaultJsonFormatException<T> : WebFaultException<T>
{
public WebFaultJsonFormatException(T detail, HttpStatusCode statusCode)
: base(detail, statusCode)
{
ErrorDetailTypeValidator(detail);
}
public WebFaultJsonFormatException(T detail, HttpStatusCode statusCode, IEnumerable<Type> knownTypes)
: base(detail, statusCode, knownTypes)
{
ErrorDetailTypeValidator(detail);
}
private void ErrorDetailTypeValidator(T detail)
{
foreach (DataContractAttribute item in detail.GetType().GetCustomAttributes(typeof(DataContractAttribute), true))
{
if (item.IsReference)
throw new WebFaultJsonFormatException<PureWebErrorDetail>(new PureWebErrorDetail("The DataContractAttribute property 'IsReference' which applied on {0} can't be true when the transfer code type is JSON fromat.", typeof(T).FullName), HttpStatusCode.ExpectationFailed);
}
}
}
[Serializable, DataContract(IsReference = false)]
public class PureWebErrorDetail
{
public PureWebErrorDetail(string message, params object[] args)
{
this.Message = string.Format(message, args);
}
[DataMemberAttribute]
public string Message { get; set; }
}
因為我們在JSON做數據傳輸的時候, DataContract中的IsReference是不可以為true的,其意思是相對於XML來說的,XML是可以支持數據的循環引用, 而JSON是不支持的,所以WebFaultJsonFormatException的作用就在於判斷當前我們的JSON數據類型的DataContract的IsReference是否為true, 如果是,則返回一個我們定義好的錯誤信息. 如果沒有采用這個定義,JQUery Ajax因此問題接收到的 HTTP Status Code 是15???的一個錯誤代碼, 但這個錯誤代碼並不是我們正常的 HTTP Status Code 范圍.
異常處理的一個誤區
最早的時候,由於沒想到用這個方式處理,也是長久寫代碼犯下的一個弊病, 給每個方法加了一個固定的泛型返回值類型
復制代碼 代碼如下:
[DataContract]
public class TmResult
{
[DataMember]
public bool Success { get; set; }
[DataMember]
public string ErrorMessage { get; set; }
[DataMember]
public string FullMessage { get; set; }
[DataMember]
public string CallStack { get; set; }
}
[DataContract]
public class TmResult<T> : TmResult
where T : class
{
[DataMember]
public T Model { get; set; }
}
每次返回都會有一個Success代表是否成功, ErrorMessage代表錯誤情況下的錯誤信息, 這樣做的方式其實就是每次返回的 HTTP Status Code 都是200, 後來知道想到上面的解決辦法之後,才覺得我們更本不需要搞的這麼復雜,既然是Web, 那干嗎不把程序寫的更符合HTTP協議的定義, 那樣豈不更簡單。
所以在此也體會到各種標准的好處, 熟悉標准,熟悉編程模型及各種API, 我們的開發會更簡單,更輕松.
以上都是按個人理解所寫,有不對之處請指正.