程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 當 jquery.unobtrusive-ajax.js 遇上Web API,jqueryajaxapi

當 jquery.unobtrusive-ajax.js 遇上Web API,jqueryajaxapi

編輯:關於.NET

當 jquery.unobtrusive-ajax.js 遇上Web API,jqueryajaxapi


最近在熟悉Abp框架,其基於DDD領域驅動設計。。。前段可以繞過mvc直接調用根據app層動態生成的webapi,有點神奇~,Web API之前有簡單接觸過,WCF的輕量級版,一般用於做一寫開發性的服務接口,形式上類似與MVC,只是不渲染視圖(其他基於restful設計什麼的我不想去扯)。

因此我的想法是頁面用mvc view帶model驗證,提交操作使用jquery.unobtrusive-ajax.js自動收集form表單內容直接調webapi;因為人少做的東西不大,view model就是dto,這樣配合jquery.validate.unobtrusive.js基本可以不用寫前端js驗證,部分代碼如下:

@model ArticleEdit
@section styles{
    <link href="~/Content/bootstrap-tagsinput.css" rel="stylesheet" />
}
<form class="form-horizontal" action="/api/services/app/article/CreateAndGetIdAsync" method="post" novalidate="novalidate" data-ajax="true" data-ajax-success="AjaxCallback" data-ajax-method="Post" role="form">
    <div class="form-group">
        @Html.LabelFor(o => o.Title, new { @class = "col-sm-2 control-label" })
        <div class="col-sm-10">
            @Html.TextBoxFor(o => o.Title, new { @class = "form-control" })
            @Html.ValidationMessageFor(o => o.Title)
        </div>
    </div>
    <div class="hr-line-dashed"></div>
    <div class="form-group">
        @Html.LabelFor(o => o.Keywords, new { @class = "col-sm-2 control-label" })
        <div class="col-sm-10">
            @Html.TextBoxFor(o => o.Keywords, new { @class = "form-control", data_role = "tagsinput", placeholder = "Tab鍵或英文','分割" })
            @Html.ValidationMessageFor(o => o.Keywords)
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(o => o.Description, new { @class = "col-sm-2 control-label" })
        <div class="col-sm-10">
            @Html.TextBoxFor(o => o.Description, new { @class = "form-control" })
            @Html.ValidationMessageFor(o => o.Description)
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(o => o.Content, new { @class = "col-sm-2 control-label" })
        <div class="col-sm-10">
            @Html.TextAreaFor(o => o.Content, new { style = "height:300px;" })
            @Html.ValidationMessageFor(o => o.Content)
        </div>
    </div>
    <div class="hr-line-dashed"></div>
    <div class="form-group">
        <div class="col-sm-4 col-sm-offset-2">
            <button class="btn btn-primary" type="submit">保存內容</button>
            <button class="btn btn-white" type="reset">重置</button>
        </div>
    </div>
</form>
@section scripts{
  //jquery.js & bootstrap.js here <script src="~/Scripts/jquery.unobtrusive-ajax.js"></script> <script src="~/Scripts/jquery.validate.unobtrusive.js"></script> <script src="~/Scripts/bootstrap-tagsinput.js"></script> <script type="text/javascript"> function AjaxCallback(data) { console.log("新增數據id:"+data.result); } </script> }

ArticleEdit:

[AutoMap(typeof(Article))]
    public class ArticleEdit
    {
        [Display(Name = "文章標題")]
        [Required(ErrorMessage = "{0} 不能為空")]
        [MaxLength(Article.MaxTitleLength, ErrorMessage = "{0} 不能超過{1}個字符")]
        public string Title { get; set; }

        /// <summary>
        /// 關鍵詞
        /// </summary>
        [Display(Name = "關鍵詞")]
        [StringLength(Article.MaxKeywordsLength, ErrorMessage = "{0} 不能超過{1}個字符")]
        public string Keywords { get; set; }

        /// <summary>
        /// 簡介描述
        /// </summary>
        [Display(Name = "簡介描述")]
        [StringLength(Article.MaxDescriptionLength, ErrorMessage = "{0} 不能超過{1}個字符")]
        public string Description { get; set; }

        /// <summary>
        /// 正文內容
        /// </summary>
        [Display(Name = "正文內容")]
        [DataType(DataType.MultilineText)]
        [AllowHtml]
        public string Content { get; set; }
    }
View Code

Abp應用層對應接口:

Task<int> CreateAndGetIdAsync(ArticleEdit input); //這裡會生成一個post api

這樣一切都大功告成了……

 ////////////////////////////////////////////////////////////////////////////////////////////////////////我是華麗的分割線//////////////////////////////////////////////////////////////////////////////////////////////////////////////////

才怪呢 。

解決思路:

應用層接收不到數據。經過反復測試:改為調用mvc post action正常,說明view內容沒寫錯,將ArticleEdit替換成string等簡單類型正常,根據abp官網的有關dynamic api說明 安裝了WebApi測試工具 Swagger 用它來調用該api發現也正常;這讓我更疑惑了,難道是ajax提交的datatype不對,再嘗試直接用 jquery ajax 測試: $.post("http://****/CreateAndGetIdAsync",{Title:"",Keywords:"",Discription:"",Content:""},function(){console.log("新增數據id:"+data.result);}); 失敗,***************最後發現正確的傳參格式如下:

$.ajax({
    type: "method",
    url: "http://****/CreateAndGetIdAsync",
    data: '{Title:"",Keywords:"",Discription:"",Content:""}',//注意這裡是字符串
    dataType: "json",
    contentType: "application/json",//$.post()沒法用就是因為沒法設置這個屬性
    success: function (response) {
        console.log("新增數據id:"+data.result);
    }
});

 問題找到了,再次被webapi坑了一把,它的ModelBinder沒有MVC的強大(詳細https://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api),mvc的ModelBinder可以同時從同時從url及post body查找數據綁定復雜數據類型的model,至於微軟沒什麼不把這兩個弄成一樣還是因為webapi是基於restful設計¥@…&。

解決辦法:一種是替換掉webapi默認的ModelBinder,相信直接拿mvc的ModelBinder照抄過來注冊給它就能搞定,暫時不想用這種破壞其風格的方式,我軟這樣設計肯定有他的道理;我用的另外一種是去改jquery.unobtrusive-ajax.js的源代碼判斷webapi請求,幸好該文件代碼很少(這也不算是一種優雅的方式),改動如下:

1.在jquery.unobtrusive-ajax.js之前引入jquery.serialize-object.js (一個自動序列化表單的插件,也可以參照 這裡 自己寫,jquery的  serializeArray() 的格式不對;後面發現這個插件也不是很符合asp.net mvc model在數組生成input name命名方式)。

2.找到jquery.unobtrusive-ajax.js發出ajax請求的地方 $.ajax(options); 改為:

        if (method == "POST" && element.getAttribute("data-ajax-webapi")) { options.contentType = "application/json;charset=utf-8"; options.data = $(element).serializeJSON(); }//這句是添加的
        $.ajax(options);

3.最後使用的時候給第一段代碼中的form加上 data-ajax-webapi="true" 。

總結:

1。webapi的設計跟mvc還是很大區別,包括其他很多地方,自己還需要多多熟悉

2。webapi理應該支持$.post()的json參數傳遞啊~~~~

3。有時間還是學學angularjs吧。

4。生命不息折騰不止

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved