AdminLTE

  一个基于 bootstrap 的轻量级后台模板,这个前端界面个人感觉很清爽,对于一个大后端的我来说,可以减少较多的时间去承担前端的工作但又必须去独立去完成一个后台系统开发的任务,并且,文档还算比较齐全,对着demo可以完成一个基本的前端框架搭建了。大家如有更为好看的又方便后端上手的前端框架,也可以在留言区分享一下呗。

AdminLTE 文档

在线中文Demo: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/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/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>

在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[].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())
});
return RedirectToPage("./Index");
}
Message = "登录失败,用户名密码不正确。";
}
return Page();
}
  userService和CookieService都是在业务层定义的,gayhub会在文章末尾。

在.Net Core Razor中,xx.cshtml.cs中默认触发的是Get和Post方法,

  • OnGet
  • OnPost
  • OnGetAsync
  • OnPostAsync

如果是需要自定义的,举个栗子,定义为:OnPostLoginAsync,然后在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请求, 400 Bad Request

        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": ": 以降序排列此列"
}
}
});

Last

附上这些天来的成果,发现,我并不适合写前端,太丑了,哈哈。

最后,Show me the code。

Banana

 

  

Demo中会使用到这两个个人封装的组件:

Banana.Uow是基于Dapper封装的工作单元和仓储;

Banana.Utility是常用的工具类,有Redis,加解密,拼音等等;

欢迎大家在Issues中提出意见,大家共同进步。

本文已独家授权给脚本之家(ID:jb51net)公众号发布

ASP.Net Core Razor+AdminLTE 小试牛刀的更多相关文章

  1. C# -- HttpWebRequest 和 HttpWebResponse 的使用 C#编写扫雷游戏 使用IIS调试ASP.NET网站程序 WCF入门教程 ASP.Net Core开发(踩坑)指南 ASP.Net Core Razor+AdminLTE 小试牛刀 webservice创建、部署和调用 .net接收post请求并把数据转为字典格式

    C# -- HttpWebRequest 和 HttpWebResponse 的使用 C# -- HttpWebRequest 和 HttpWebResponse 的使用 结合使用HttpWebReq ...

  2. ASP.NET Core - Razor 页面简介

    简介 随着ASP.NET Core 2 即将来临,最热门的新事物是Razor页面.在之前的一篇文章中,我们简要介绍了ASP.NET Core Razor 页面. Razor页面是ASP.NET Cor ...

  3. ASP.NET Core - Razor页面之Handlers处理方法

    简介 在前一篇文章中,我们讨论了Razor页面.今天我们来谈谈处理方法(Handlers). 我们知道可以将代码和模型放在 .cshtml 文件里面或与 .cshtml 匹配的 .cshtml.cs ...

  4. ASP.NET Core Razor中处理Ajax请求

    如何ASP.NET Core Razor中处理Ajax请求 在ASP.NET Core Razor(以下简称Razor)刚出来的时候,看了一下官方的文档,一直没怎么用过.今天闲来无事,准备用Rozor ...

  5. ASP.NET Core Razor页面禁用防伪令牌验证

    在这篇短文中,我将向您介绍如何ASP.NET Core Razor页面中禁用防伪令牌验证. Razor页面是ASP.NET Core 2.0中增加的一个页面控制器框架,用于构建动态的.数据驱动的网站: ...

  6. ASP.NET Core Razor 页面使用指南

    ASP.NET Core Razor 页面作为 ASP.NET Core 2.0的一部分发布,它是基于页面的全新的Web开发框架.如果您想学习如何使用 ASP.NET Core Razor 页面,可以 ...

  7. 学习ASP.NET Core Razor 编程系列一

    一. 概述 .NET Core 1.0发布的时候就想进行学习的,不过根据微软的以往的发布规律1.0版可以认为是大众测试版,2.0才算稳定.现在2.1都已经发布了预览版,之前对其"不稳定&qu ...

  8. 学习ASP.NET Core Razor 编程系列二——添加一个实体

    在Razor页面应用程序中添加一个实体 在本篇文章中,学习添加用于管理数据库中的书籍的实体类.通过实体框架(EF Core)使用这些类来处理数据库.EF Core是一个对象关系映射(ORM)框架,它简 ...

  9. 学习ASP.NET Core Razor 编程系列四——Asp.Net Core Razor列表模板页面

    学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...

随机推荐

  1. Future与Promise

    https://code.csdn.NET/DOC_Scala/chinese_scala_offical_document/file/Futures-and-Promises-cn.md#ancho ...

  2. Fiddler抓包使用教程-Android应用抓包

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/74439165 本文出自[赵彦军的博客] Fiddler 也可以支持对手机应用进行 ...

  3. git添加本地的项目到git远程管理仓库

    目标:将本地存在的项目添加到git远程仓库管理 步骤: 1. 需要一个git远程仓库管理地址 例如:https://github.com/xingfupeng/test.git git@github. ...

  4. All is Over

    Noip2017结束,AFO.WC2017上神犇们唱的膜你抄   就是退役的背景音乐了 不管以后何去何从,Oier的生涯对我来说已经终了,找个日子好好回忆一下这么多年的Oi时光,然后写篇博文祭奠 自此 ...

  5. Flask入门之Jinjia模板的一些语法

    1. 变量表示 {{ argv }} 2. 赋值操作 {% set links = [ ('home',url_for('.home')), ('service',url_for('.service' ...

  6. java并发之DelayQueue实际运用示例

    在学习Java 多线程并发开发过程中,了解到DelayQueue类的主要作用:是一个无界的BlockingQueue,用于放置实现了Delayed接口的对象,其中的对象只能在其到期时才能从队列中取走. ...

  7. @SpringBootApplication注解理解

    @SpringBootApplication包含三个有用的注解,包括 @SpringBootConfiguration:看源码其实就是@Configuration,表示当前类是一个配置类,就像xml配 ...

  8. SSM-SpringMVC-30:SpringMVC中InitBinder的骇客级优化

     ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 上篇博客利用initbinder做了局部的日期类型转换,但是兼容性不要,只支持yyyy-MM-dd这种,所以 ...

  9. JavaScript-点击任意点显示隐藏

    //开/关 var only = document.getElementById('only'); var centerBox = document.getElementById('centerBox ...

  10. Tar专题

    下面的脚本根据当前的系统时间生成压缩文件名,并备份文件到指定目录: DIR=/www/webbackup/web/ FILE_NAME=`date +%y%m%d%H` FILE_NAME=$DIR/ ...