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. 从Freelancer的热门Skill看看你应该学什么?

    以下数据是2012-1-31号数据. Websites, IT & Software: PHP (2402)HTML (1639)SEO(877)MySQL (836)Link Buildin ...

  2. 从输入一个URL到页面完全显示发生了什么?

    这是经典的前端问题,主要是对浏览器的工作原理有个理解! 网络通信走的一般是五层因特网协议,详见下图.图片来自于https://images2018.cnblogs.com/blog/882926/20 ...

  3. HTML5学习系列之表单与文件

    article元素 article元素代表文档.页面或应用程序中独立的.完整的.可以独自被外部引用的内容.它可以是一篇博客或报刊中的文章.一篇论坛帖子.一段用户评论或独立的插件,或者其他任何独立的内容 ...

  4. VueJs(9)---vue-router(进阶1)

    vue-router 本文是基于官网学习,官网具体学习目录:vue-router 一.安装 基于vue-cli脚手架安装还是蛮简单的:在文件当前目录下运行: npm install vue-route ...

  5. DDGScreenShot — 复杂屏幕截屏(如view ScrollView webView wkwebView)

    写在前面 最近有这么一个需求,分享页面,分享的是web订单截图,既然是web 就会有超出屏幕的部分, 生成的图片还要加上我们的二维码,这就涉及到图片的合成了. 有了这样的需求,就是各种google.也 ...

  6. c++11线程池

    #pragma once #include <future> #include <vector> #include <atomic> #include <qu ...

  7. Spring Boot 2.0 教程 - 深入SpringAplication

    原文连接:https://www.codemore.top/cates/Backend/post/2018-05-20/spring-boot-SpringApplication 可以通过Spring ...

  8. LESS的好处

    今日目标: 1:今天的学习内容是在工作完成的情况下,学习Less(之所以学习Less是因为项目中使用的是Less)-------------当前进度(0%) 注意项: 务必确保在 less.js 之前 ...

  9. CSS+DIV定位分析(relative,absolute,static,fixed)

    在用CSS+DIV进行布局的时候,一直对position的四个属性值relative,absolute,static,fixed分的不是很清楚,以致经常会出现让人很郁闷的结果.今天研究了一下,总算有所 ...

  10. 超实用的JavaScript代码段 Item2 --伸缩菜单栏

    伸缩菜单栏 点击标题时判断该标题下的菜单是否显示,如果是显示的则将其隐藏,如果是隐藏的则将其显示出来. <!doctype html> <html lang="en&quo ...