本節內容:
AJAX操作相關問題
執行一個AJAX調用在現在的應用裡非常常見,尤其在SPAs(Single-Page Applications 單頁面應用)裡,它幾乎是唯一與服務器通信的方式。一個AJAX調用由幾個重復的步驟組成:
在客戶端,基本上,javascript代碼應該提供一個URL,隨意的一個數據和選擇一個方法(POST,GET...)來執行一個AJAX調用,它必須等待並處理返回值,當向服務器執行一個調用時,可能會出錯(通常網絡錯誤),或其它服務端錯誤,服務端返回一個攜帶錯誤信息的失敗的響應,客戶端應該處理這些或通知用戶(可顯示一個錯誤對話框),如果沒有錯誤,服務端發送一個返回數據,客戶端也必須處理它。操作過程中,通常會屏蔽或整個屏幕並顯示一個AJAX正在操作的信息,直到它完成。
服務端代碼獲取到一個請求,執行一些服務端代碼,捕獲任何的異常並返回一個有效的返回給客戶端。如果有出錯的情況,可能會發送錯誤信息給客戶端,如果是一個驗證錯誤,服務器可能會添加一個驗證問題。如果成功,可能會發送一個返回值給客戶端。
ABP的方式
ABP使用通過包裝了AJAX調用的abp.ajax,自動處理這些步驟,下面是一個AJAX調用示例:
var newPerson = { name: 'Dougles Adams', age: 42 }; abp.ajax({ url: '/People/SavePerson', data: JSON.stringify(newPerson) }).done(function(data) { abp.notify.success('created new person with id = ' + data.personId); });
abp.ajax獲取一個可選的對象,你可以傳遞任何的參數(它會被jQuery的$.ajax方式驗證),此處有些默認:dataType:'json',type:'POST',contentType:'application/json'(所以,在發送到服務器前,我們調用JSON.stringify把javascript轉換為JSON字符串),我們可以給abp.ajax傳遞options來覆蓋這些默認.
abp.ajax返回promise,所以,你可以寫done,fail,then....處理程序,在這個例子中,我們創建了一個簡單的AJAX請求,調用PeopleController的SavePerson操作,在done處理程序裡,我們獲取數據庫裡新創建的person的id並顯示一個成功的通知(查看notification API)。我們看一下這個AJAX調用的MVC控制器:
public class PeopleController : AbpController { [HttpPost] public JsonResult SavePerson(SavePersonModel person) { //TODO: save new person to database and return new person's id return Json(new {PersonId = 42}); } }
SavePersonModel包含Name和Age屬性,SavePerson標記為HttpPost,因此abp.ajax的默認方法為POST。我簡化方法的實現,只返回一個匿名對象。
這樣直截了當,但有些重要的東西ABP在背後進行了處理,讓我們深入細節...
AJAX 返回信息
即使我們返回一個PersonId=2對象,ABP把它包裝成一個MvcAjaxResponse對象,AJAX響應實質上像下面這樣:
{ "success": true, "result": { "personId": 42 }, "error": null, "targetUrl": null, "unAuthorizedRequest": false, "__abp": true }
此處,所有屬性都是小駱峰式命名(因為這是javascript世界裡約定好的),即使它們在服務端是大駱峰式命名。讓我們解釋一下這些屬性:
abp.ajax函數識別和處理這個返回格式,如果不出錯,abp.ajax裡你的done處理程序獲取真正的控制器的返回值(一個包含personId屬性的對象)。
處理錯誤
如上所述,ABP在服務器處理異常並返回一個包含錯誤信息的對象:
{ "targetUrl": null, "result": null, "success": false, "error": { "message": "An internal error occured during your request!", "details": "..." }, "unAuthorizedRequest": false, "__abp": true }
如你所見,success為false且result為null,abp.ajax處理這個對象且通過abp.message.error函數顯示一個錯誤信息給用戶。如果服務端拋出一個userFriendlyException類型的異常,它直接給用戶顯示錯誤信息,否則,它隱藏實際錯誤(把錯誤寫到日志)並顯示一個“發生一個內部錯誤..."信息給用戶,這些ABP都會自動處理。
你可能會想為某些特定的AJAX調用,禁止顯示信息,此時你可以把abpHandleError:false添加到abp.ajax的options裡。
HTTP 狀態碼
ABP為異常返回給定的狀態碼:
WrapResult和DontWrapResult特性
你可以通過為一個操作或控制器的所有操作使用WrapResult和DontWrapResult特性來控制包裝。
Asp.net Mvc 控制器
如果Asp.net Mvc 操作方法返回類型為JsonResult(或異步的Task<JsonResult>),ABP默認地會進行包裝(如上所述),你可以使用WrapResult特性改變這種行為,如下所示:
public class PeopleController : AbpController { [HttpPost] [WrapResult(WrapOnSuccess = false, WrapOnError = false)] public JsonResult SavePerson(SavePersonModel person) { //TODO: save new person to database and return new person's id return Json(new {PersonId = 42}); } }
作為快捷方式,我們可以僅使用[DontWrapResult]來達到與此例相同目的。
你可以從啟動配置(使用Configuration.Modules.AbpMvc()...)改變這種默認行為。
Asp.net Web Api 控制器
ABP默認情況下不包裝成功的Web Api操作的結果,如果有需要,你可以添加WrapResult到操作或控制器上,但是默認包裝異常。
你可以從啟動配置(使用Configuration.Modules.AbpWebApi()...)改變這種默認行為。
動態Web Api層
ABP默認情況下包裝動態Web Api層的方法結果,你可以通過在你的應用服務接口上使用WrapResult和DontWrapResult特性來改這種行為。
Asp.net Core 控制器
ABP自動包裝JsonResult、ObjectResult和任何未實現IActionResult的結果,更多信息查看Asp.net Core 文檔。
你可以從啟動配置(使用Configuration.Modules.AbpAspNetCore()...)改變這種默認行為。
動態Web Api層
雖然ABP提供了一種簡單使用AJAX的機制,但在一個真實世界的應用裡,為每個AJAX調用寫一個javascript函數還是很典型的,例如:
//Create a function to abstract AJAX call var savePerson = function(person) { return abp.ajax({ url: '/People/SavePerson', data: JSON.stringify(person) }); }; //Create a new person var newPerson = { name: 'Dougles Adams', age: 42 }; //Save the person savePerson(newPerson).done(function(data) { abp.notify.success('created new person with id = ' + data.personId); });
為每個AJAX調用寫一個函數,這是一個好的實踐,但耗時且無趣, ABP可以自動地為應用服務和控制器生成這些類型的函數。
查閱動態Web Api層文檔獲取更多Web Api信息,查閱Asp.net Core文檔獲取有關Asp.net Core集成信息。
kid1412附:英文原文:http://www.aspnetboilerplate.com/Pages/Documents/Javascript-API/AJAX