用JSON做數據傳輸格式中的一些問題總結
Json 憑借其自身的優勢,在Web數據處理方面已經占據了一定的位置,這段時間涉及到用Json做為數據傳輸格式的項目有3個,其中有部分頁面就采用了Json 數據傳輸格式, 這里我總結下這段時間采用這種方式的一些問題總結,
向客戶端提供JSON數據的方式
一. 用WCF提供Json數據
用WCF向客戶端提供Json數據我們需要注意,
A. 契約的定義, 在WebInvokeAttribute 或者 WebGetAttribute中的ResponseFormat設置為WebMessageForm.Json,
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)]
[WebGet(ResponseFormat = WebMessageFormat.Json, UriTemplate = "IsExistSSID/{SSID}", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)]
B. EndPointBehavior使用WebHttp
<behavior name="UIAjaxEndpointBehavior">
<webHttp />
<PolicyEndPointBehavior />
</behavior>
C. Binding 方式使用webHttpBinding
<service name="XX.DeviceUIService" behaviorConfiguration="UIAjaxServiceBehavior"> <endpoint address="" behaviorConfiguration="UIAjaxEndpointBehavior" binding="webHttpBinding" contract="DeviceUIServiceContract" /> </service>
二. 用.Net MVC Action提供 JSON 數據
1. 在ValueProviderFactories.Factories.Add(new JsonValueProviderFactory())中加入 Json 數據的處理, MVC 3默認是加入的, 如果你使用的是 MVC3, 則無需理會這一點.
2. 采用JsonResult作為你Action的返回值。
3.返回是使用return Json(XXX); XXX為你要返回的數據,其數據類型必須為可序列化類型.
三. 可采用以asmx為后綴名的簡單WebService來實現,
四. 使用HttpHandler機制來實現.
因為WCF已被微軟定義為微軟系下的通信平臺,而后兩種隨可以實現,但是是較早的實現方式,所以在此我使用了WCF,直接把所提供的數據,視作系統的數據提供接口.
而在.NET MVC的環境里, 已經直接支持輸出 Json 形式的數據,所以在非.NET MVC的環境選擇WCF提供, 而在.NET MVC環境直接選擇用JSON Action支持.
WEB客戶端處理
用JQuery Ajax處理
把 dataType設置為 'json' 格式,在接收數據時會自動把result轉換為json object格式.
$.ajax({
url: ‘urladdress’
type: 'GET',
contentType: 'application/json',
dataType: 'json',
cache: false,
async: false,
error: JQueryAjaxErrorHandler,
success: function (result) { }
});
異常處理的考慮
在這里我主要考慮在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, 我們的開發會更簡單,更輕松.
浙公網安備 33010602011771號