其次我们要对异常做一些处理,让服务端能返回正确的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);
}
{
//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; }
}
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; }
}
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, 我们的开发会更简单,更轻松.