ASP.Net Core Razor+AdminLTE 小試牛刀
AdminLTE
一個基於 bootstrap 的輕量級後臺模板,這個前端介面個人感覺很清爽,對於一個大後端的我來說,可以減少較多的時間去承擔前端的工作但又必須去獨立去完成一個後臺系統開發的任務,並且,文件還算比較齊全,對著demo可以完成一個基本的前端框架搭建了。大家如有更為好看的又方便後端上手的前端框架,也可以在留言區分享一下唄。
AdminLTE 文件
線上中文Demo: ofollow,noindex"> http://adminlte.la998.com/
線上中文文件: http://adminlte.la998.com/documentation/index.html
Github: https://github.com/almasaeed2010/AdminLTE/releases
AdminLTE 佈局
AdminLTE依賴於兩個主要框架:JQ和Bootstrap,其他外掛可以按需增加。
從文件可以知道,使用AdminLTE主要有四個部分:
- 包裝
.wrapper
。 包裹整個網站的div。 - 主標題
.main-header
。 包含徽標和導航欄。 - 邊欄
.sidebar-wrapper
。 包含使用者面板和側邊欄選單。 - 內容
.content-wrapper
。 包含頁首和內容。
在文件中,可以找到下載地址,本文示例是使用 最新的版本 V2.4.5 。
Asp.Net Core Razor
新建專案Asp.net Core Web應用程式,預設就是Razor Pages,然後新增相應的模組,如圖: 本文使用的SDK版本為:dotNet Core 2.1。
First
在Asp.Net Core專案中,引用AdminLTE,在wwwroot僅新增如圖三個資料夾即可:
- bower_components 基本元件。
- dist adminlte的主要檔案。
- plugins 其他外掛。
Second
在_Layout.cshtml檔案中新增引入相關檔案:
<!-- Tell the browser to be responsive to screen width --> <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"> <!-- Bootstrap 3.3.7 --> <link rel="stylesheet" href="~/adminlte/bower_components/bootstrap/dist/css/bootstrap.min.css"> <!-- Font Awesome --> <link rel="stylesheet" href="~/adminlte/bower_components/font-awesome/css/font-awesome.min.css"> <!-- Ionicons --> <link href="~/adminlte/bower_components/Ionicons/css/ionicons.min.css" rel="stylesheet" /> <!-- Theme style --> <link rel="stylesheet" href="~/adminlte/dist/css/AdminLTE.min.css"> <!-- AdminLTE Skins. Choose a skin from the css/skins folder instead of downloading all of them to reduce the load. --> <link rel="stylesheet" href="~/adminlte/dist/css/skins/_all-skins.min.css"> <!-- Pace style --> <link href="~/adminlte/plugins/pace/pace.min.css" rel="stylesheet" /> <link href="~/css/common.css" rel="stylesheet" /> <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> <!-- Google Font --> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic">
在body中,新增js:
<!-- jQuery 3 --> <script src="~/adminlte/bower_components/jquery/dist/jquery.min.js"></script> <!-- jQuery UI 1.11.4 --> <script src="~/adminlte/bower_components/jquery-ui/jquery-ui.min.js"></script> <!-- Resolve conflict in jQuery UI tooltip with Bootstrap tooltip --> <script> $.widget.bridge('uibutton', $.ui.button); </script> <!-- Bootstrap 3.3.7 --> <script src="~/adminlte/bower_components/bootstrap/dist/js/bootstrap.min.js"></script> <!-- Slimscroll --> <script src="~/adminlte/bower_components/jquery-slimscroll/jquery.slimscroll.min.js"></script> <!-- FastClick --> <script src="~/adminlte/bower_components/fastclick/lib/fastclick.js"></script> <!-- AdminLTE App --> <script src="~/adminlte/dist/js/adminlte.min.js"></script> <!-- Skin --> <script type="text/javascript" src="~/adminlte/dist/js/sidebarskins.js" charset="gbk"></script>
sidebarskins.js是本人漢化的側邊欄面板
坑1:一般情況,發現某些功能執行不起來的都是引用不正確導致的,這個要耐心對照好Demo來檢查,或者直接用Demo來修改吧。
Third
開始使用AdminLTE,這裡直接貼圖吧,圖上有註釋和程式碼摺疊比較直觀點,重要的地方在放程式碼。
最後就可以執行專案來預覽一下效果了:
都使用到bootstrap,必須得看看移動端的效果,還不錯吧。
坑2:需要注意的是,點選這個小圖示 可以實現左側邊欄收縮展開的功能,當只有側邊欄可以正常收縮展開但Logo無動於衷的時候,你可能是少了【 sidebar-mini 】樣式和【 logo-mini 】logo小圖的引用
新增一個登陸
登入介面寫得比較簡約,我比較喜歡這種風格。前端寫得不多,所以還得前端的女票指導一二,不然就是後端的設計的介面了,你懂的。
在Pages資料夾中,新增一個Razor介面,並擼好介面程式碼:
@page @model AdminLTE.Net.Web.Pages.LoginModel @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>登入 - AdminLTE.Net.Web</title> <meta name="developer" content="EminemJK"> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" /> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap-theme.min.css" rel="stylesheet" /> <link href="~/adminlte/dist/css/AdminLTE.min.css" rel="stylesheet" /> <link href="~/css/login.css" rel="stylesheet" /> </head> <body> <div> <div class="row"> <div class="loginHeader"> <img class="logo-img" src="~/images/banana_logo.ico" /> <h1 class="logo-name">Banana</h1> <div class="clearfix"></div> </div> </div> <div class="row login-bg"> <div class="loginInBox"> @if (!string.IsNullOrEmpty(Model.Message)) { <p class="login-box-msg" style="color:red">@Model.Message</p> } else { <p class="login-box-msg">Sign in to start your session</p> } <form method="post"> <div class="form-group has-feedback"> <input type="text" class="form-control" asp-for="Login.UserName"> <span class="glyphicon glyphicon-user form-control-feedback"></span> </div> <div class="form-group has-feedback"> <input type="password" class="form-control" asp-for="Login.Password"> <span class="glyphicon glyphicon-lock form-control-feedback"></span> </div> <button type="submit" class="btn btn-primary btn-block btn-flat login-btn">Sign In</button> </form> </div> </div> </div> <footer class="footer"> <strong>Copyright © 2018 <a href="http://www.cnblogs.com/EminemJK/">EminemJK</a>.</strong> All rights reserved. </footer> </body> </html> View Code
在Startup中引入Authentication身份驗證:
services.AddAuthentication(CookieService.AuthenticationScheme) .AddCookie(CookieService.AuthenticationScheme, o => { o.LoginPath = new PathString("/Login"); });
Configure方法內呼叫
app.UseAuthentication();
在Login.cshtml.cs中增加一個OnPostAsync的方法:
[HttpPost] public async Task<IActionResult> OnPostAsync() { if (!ModelState.IsValid) { Message = ModelState.Root.Errors[0].ErrorMessage; } else { var user = userService.Login(Login.UserName, Login.Password); if (user != null) { VUserModel model = new VUserModel() { Id = user.Id, UserName = user.UserName, Time = DateTime.Now }; var identity = new ClaimsIdentity(CookieService.AuthenticationScheme); identity.AddClaim(new Claim(ClaimTypes.Sid, CookieService.GetDesEncrypt(model))); await HttpContext.SignInAsync(CookieService.AuthenticationScheme, new ClaimsPrincipal(identity), new AuthenticationProperties() { //記住我 IsPersistent = true, //過期時間 ExpiresUtc = DateTimeOffset.Now.Add(TimeSpan.FromMinutes(30)) }); return RedirectToPage("./Index"); } Message = "登入失敗,使用者名稱密碼不正確。"; } return Page(); }
userService和CookieService都是在業務層定義的,gayhub會在文章末尾。
在.Net Core Razor中,xx.cshtml.cs中預設觸發的是Get和Post方法,
- OnGet
- OnPost
- OnGetAsync
- OnPostAsync
如果是需要自定義的,舉個栗子,定義為:OnPost Login Async,然後在Form表單提交的【按鈕】增加 asp-page-handler="Login" , 詳細的推薦大家閱讀這篇文章: ASP.NET Core - Razor頁面之Handlers處理方法 。
接著,然後再Index和需要身份驗證的地方都加上Authorize特性即可:
namespace AdminLTE.Net.Web.Pages { [Authorize(AuthenticationSchemes = CookieService.AuthenticationScheme)] public class IndexModel : BasePageModel { public void OnGet() { } } }
踩坑
一、Ajax Post請求,HttpCore 400
function uploadfile() { var file = $("#input-userimg")[0].files[0]; var data = new FormData(); data.append('file', file); $.ajax({ url: "/Account/UserList?handler=Upload", type: 'POST', data: data, contentType: false, processData: false, success: function (returndata) { $("#user-img").attr('src', returndata.path); }, error: function (a, b, c) { alert('上傳失敗') } }); };
折騰許久,原因是Razor被設計為可以自動防止跨站請求偽造(CSRF / XSRF)攻擊。你不必編寫任何其他程式碼。Razor頁面中自動包含防偽令牌生成和驗證。這裡請求失敗,是因為POST沒有提交AntiForgeryToken。
解決方法:
1.增加"XSRF-TOKEN"標識到框架中
//增加了"XSRF-TOKEN"標識,值為表單自動生成的防偽標記 services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
2.頁面*.cshtml頭部加上
@Html.AntiForgeryToken()
3.ajax引入
function uploadfile() { var file = $("#input-userimg")[0].files[0]; var data = new FormData(); data.append('file', file); $.ajax({ url: "/Account/UserList?handler=Upload", type: 'POST', data: data, contentType: false, processData: false, beforeSend: function (xhr) { xhr.setRequestHeader("XSRF-TOKEN", $('input:hidden[name="__RequestVerificationToken"]').val()); }, success: function (returndata) { $("#user-img").attr('src', returndata.path); }, error: function (a, b, c) { alert('上傳失敗') } }); };
然後既可以正常訪問Handler
二、DataTables引數例項加說明
var table = $('#userListTable').DataTable({ "processing": true, "serverSide": true, "ajax": function (data, callback, settings) { //data的引數請參考: https://segmentfault.com/a/1190000004478726 var param = {}; param.draw = data.draw; param.pageNum = (data.start / data.length) + 1; param.pageSize = data.length; param.sex = $('#select-sex option:selected').val(); param.phone = $('#input-phone').val(); param.name = $('#input-name').val(); $.ajax({ type: "GET", data: param, url: "/Account/UserList?handler=UserPage", dataType: "json", success: function (data) { //成功後回撥自動渲染 callback(data); } }); }, 'columns': [ { 'data': 'id' }, { 'data': 'name' }, { 'data': 'userName' }, { 'data': 'sexString' }, { 'data': 'phone' }, { 'data': 'createTime' }, { 'data': 'enableString', 'render': function (data, type, row) { if (row.enable == 1) return '<span style="color:#19be6b" >' + row.enableString + '</span>'; else return '<span style="color:#ed3f14" >' + row.enableString + '</span>'; } }, { 'data': null, 'render': function (data, type, row) { return '<a id="btn-edit" class="btn btn-success btn-xs"title="編輯" onClick=btn_edit(' + row.id + ')><i class="fa fa-edit"></i>編輯</a>' + '<a id="btn-edit" class="btn btn-danger btn-xs"title="刪除" onClick=btn_edit(' + row.id + ')><i class="fa fa-trash "title="刪除" style="cursor:pointer"></i>刪除</a>'; } }, ], //datatable設定引數 http://www.datatables.club/reference/option/ 'paging': true,//啟用分頁 'lengthChange': true,//設定每頁數量 'searching': false, 'ordering': false, 'info': true, 'autoWidth': false, //設定中文 'language': { "sProcessing": "玩命載入中...", "sLengthMenu": "每頁顯示顯示 _MENU_", "sZeroRecords": "沒有匹配結果", "sInfo": "顯示第 _START_ 至 _END_ 項結果,共 _TOTAL_ 項", "sInfoEmpty": "顯示第 0 至 0 項結果,共 0 項", "sInfoFiltered": "(由 _MAX_ 項結果過濾)", "sInfoPostFix": "", "sSearch": "搜尋:", "sUrl": "", "sEmptyTable": "表中資料為空", "sLoadingRecords": "玩命載入中...", "sInfoThousands": ",", "oPaginate": { "sFirst": "首頁", "sPrevious": "上頁", "sNext": "下頁", "sLast": "末頁" }, "oAria": { "sSortAscending": ": 以升序排列此列", "sSortDescending": ": 以降序排列此列" } } }); View Code
Last
附上這些天來的成果,發現,我並不是寫前端,太醜了。
最後,Show me the code。
Github: https://github.com/EminemJK/AdminLTE.Net.Web
Banana
Banana Github: https://github.com/EminemJK/Banana
Demo中會使用到這兩個個人封裝的元件:
Banana.Uow是基於Dapper封裝的工作單元和倉儲;
Banana.Utility是常用的工具類,有Redis,加解密,拼音等等;
歡迎大家在Issues中提出意見,大家共同進步。