今日閑來無事,把玩了下傳說中的HTML5、CSS3、ASP.NET MVC4,以及隨之發布的WebAPI。不得不說,新鮮的知識點太多了,不可能按部就班地去學。參照網上的幾篇文章,邊看邊做,搭建了一個簡單的demo,現將一些要點記錄下來。
首先從一個介紹CSS3的國外站點down了一個登錄頁(HTML5+CSS3構建同頁面表單間的動畫切換),做了簡單修改后就成了下面這個樣子。
頁面中沒有用到任何圖片,陰影是CSS3新加的渲染標記,文本框中的圖標乃是一種字體,這里還用到CSS中偽類的東東。比如用戶編號和對應文本框的html:
1 <label for="username" data-icon="u">用戶編號</label> 2 <input id="username" name="userCode" required="required" type="text" />
生成圖標的CSS:
1 [data-icon]:after { 2 content: attr(data-icon); 3 font-family: 'FontomasCustomRegular'; 4 color: rgb(106, 159, 171); 5 position: absolute; 6 left: 10px; 7 top: 35px; 8 width: 30px; 9 }
其中'FontomasCustomRegular'就是圖標字體。
注意,如果將上面代碼中的label設為不可見,那么相應的偽類元素也將不可見,因為偽類元素其實仍是目標元素(這里是label)的子元素(內容);input 不支持偽類元素,因為input無法容納其他元素。
難點在於怎么樣讓登錄區域垂直居中。要實現垂直居中,以前除了寫JS,沒有其它更好的辦法(還可參考登陸頁面怎么讓DIV垂直居中,還要兼容)。CSS3帶來了flexbox的概念,能讓其中的子元素靈活地排版布局。這里我們定義外圍容器的樣式,讓它作為flexbox,登錄區塊就是它的子元素。
1 #container { 2 width: 100%; 3 height: 100%; 4 position: absolute; 5 left: 0; 6 top: 0; 7 background: url("bg.jpg"); 8 display: -webkit-box; 9 -webkit-box-align: center; 10 display: -moz-box; 11 -moz-box-align: center; 12 -moz-box-pack: center; 13 display: -o-box; 14 -o-box-align: center; 15 display: -ms-box; 16 -ms-box-align: center; 17 display: -ms-flexbox; 18 -ms-flex-align: center; 19 }
為了實現垂直居中,我查閱了一些資料,當時就有點怒了。本質同樣的東西,不同廠商非得搞一套自己的命名規則。上述代碼在IE與Chrome中工作預期,但在Firefox中則沒有成功,原因未知。關於flexbox的詳細講解請看深入了解 Flexbox 伸縮盒模型,需要注意的是現行的一些概念並非所有瀏覽器都支持,CSS3距離統一標准還有很長的路要走。
驗證通過后轉到主界面,我們用localStorage.setItem("UserID", "@Model.ID");保存登錄用戶的ID。
注意頂部bar,退出鏈接靠右顯示。在以前,我們用“float:right”就搞定了,但這里沒起作用,推測由於這個bar是flexbox。后來我將退出鏈接設置成“margin-left:auto”,解決。左側菜單我用WebAPI獲取數據。
1 public class AccountController : ApiController 2 { 3 /// <summary> 4 /// 根據用戶ID獲取有權限的功能模塊 5 /// </summary> 6 public IEnumerable<ModuleTreeItem> GetUserModules(int uid) 7 { 8 var modules = UserLogic.ModuleProcessOfUser(uid); 9 return RoleVM.ChangeSysModuleToTreeItem(modules); 10 } 11 }
關於獲取數據和構造樹的細節和本主題無關,略之。按照WebApi(這里指的就是Asp.Net MVC4 WebApi,下同)的默認約定,現在可以用api/Account?uid=1(不能直接api/Account/1,因為參數名如果不是路由規則默認的話,需要顯式指定)請求該資源了。(讀者:啥,你說資源?GetUserModules這個action哪去了?)WebApi遵照Restful風格,在Rest中,任何對服務的請求都是針對資源的,請求類型包括增刪改查。這里Account就是資源,當服務端接收到Get請求時,會查找以“Get”開頭的action並匹配參數,這里就匹配到了GetUserModules,POST\DELETE\PUT的路由方式同理。如果有多個Get開頭的不同名方法,但參數一樣,客戶端就會接受到下面這個信息:
這對我這類習慣了一個類里面N多方法的人來說,相當不習慣。我想既然Rest沒有action這個概念,那么我將所有的action都轉為controller的形式,作為資源暴露出去,不過這種方式也同樣別扭。於是我增加了一個路由規則:
1 config.Routes.MapHttpRoute( 2 name: "ActionApi", 3 routeTemplate: "api/{controller}/{action}/{id}", 4 defaults: new { id = RouteParameter.Optional } 5 );
后記:在ASP.NET MVC4中,web api默認就支持api/{controller}/{action}模式,不需要顯式增加該路由規則。
雖然違背了rest的原則,但我想凡事不能照本宣科,新的路由規則既然不會帶來什么壞處,為什么不用呢?此時咱們就可以用api/Account/GetUserModules?uid=1來請求了。接着我輕快地敲出JS調用代碼。
1 var requestData = JSON.stringify({ uid: localStorage.getItem("UserID") }); 2 $.ajax({ 3 url: '/api/Account/GetUserModules', 4 data: requestData, 5 type: "post", 6 dataType: "json", 7 contentType: "application/json; charset=utf8", 8 success: function (data) { 9 var inline = new kendo.data.HierarchicalDataSource( 10 { 11 data: data, 12 schema: { 13 model: { 14 children: "Children" 15 } 16 } 17 }); 18 $("#treeview").kendoTreeView({ 19 dataSource: inline, 20 dataTextField: ["Module.Name"] 21 }); 22 23 } 24 });
運行時出現
405 - 用來訪問本頁面的 HTTP 謂詞不被允許(方法不被允許)
I know,action默認只接受Get請求,so我加上[AcceptVerbsAttribute("GET","POST")],重新請求。
404的意思是找不到請求的資源,查看詳細。
這種情況估計是參數沒傳到服務端。按照我以往的經驗,應該不會有這種問題。於是我從網上down了幾個大牛的demo,發現皆出現404錯誤,但是看后面的評論,似乎沒有童鞋提出該問題,於是哥糾結了。考慮到前段時間微軟發布的vs更新包,難道是版本更新導致傳參方式變動?正打算去找一下官方的更新文檔,一個特性FromBody映入眼簾(asp.net webapi下json傳值方式)。我抱着試試看的心情,嘗試了下。
public IEnumerable<ModuleTreeItem> GetUserModules([FromBody] int uid),運行。
看到這里,是不是有種想撞牆的趕腳?400,錯誤請求。查看詳細信息:{"Message":"請求無效。","MessageDetail":"對於“WebHabilimentERP.API.AccountController”中方法“System.Collections.Generic.IEnumerable`1[SysProcessViewModel.ModuleTreeItem] GetUserModules(Int32)”的不可以為 null 的類型“System.Int32”的參數“uid”,參數字典包含一個 null 項。可選參數必須為引用類型、可以為 null 的類型或聲明為可選參數。"}。
經過一番google、bing,甚至百度都上場了,終於找到一篇稍微有用的文章:ASP.NET WebAPI throw 404 if method parameter is string or int。按照文中方法嘗試,無果。不過它倒提醒我,是不是不用傳參數名,既將data: { uid: localStorage.getItem("UserID") }改為data: localStorage.getItem("UserID"),成功。
最終代碼如下:
服務端
1 [AcceptVerbsAttribute("GET","POST")] 2 public IEnumerable<ModuleTreeItem> GetUserModules([FromBody] int uid) 3 { 4 var modules = UserLogic.ModuleProcessOfUser(uid); 5 return RoleVM.ChangeSysModuleToTreeItem(modules); 6 }
客戶端
1 $.ajax({ 2 url: '/api/Account/GetUserModules', 3 data: localStorage.getItem("UserID"), 4 type: "post", 5 dataType: "json", 6 contentType: "application/json; charset=utf8", 7 success: function (data) { 8 var inline = new kendo.data.HierarchicalDataSource( 9 { 10 data: data, 11 schema: { 12 model: { 13 children: "Children" 14 } 15 } 16 }); 17 $("#treeview").kendoTreeView({ 18 dataSource: inline, 19 dataTextField: ["Module.Name"] 20 }); 21 22 } 23 });
敲門(非入門)完畢。
關於Post參數值傳不到后台的補充連接:Web.API and jQuery JSON Post- null value?
轉載請注明出處:http://www.cnblogs.com/newton/archive/2013/04/25/3043615.html