一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar]

千磨万击还坚劲,任尔东西南北风。这篇文章主要讲述一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar]相关的知识,希望能为你提供帮助。
前言Hi, 大家好,还是星期五,还是Rector,又在图享网准时和大家见面了。 今天给大家带来系列教程《一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar]》的第八期了,不知道你有没有按照教程将前七期的都实际练习一篇呢?如果是,你在练习的时候有没有遇到什么问题呢? 反正Rector是有收到部分童鞋发来他们练习过程中的问题反馈的哦。
【一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar]】如果你仔细阅读并实际练习了前面七期的教程,我相信,作为刚入门或者经验尚浅的你一定会有收获的。
加油吧,骚年!!! 人生苦短,就怕努力!!!
Rector这是要成为心理导师的节奏啊,一来就给大家灌饱心灵鸡汤。。。
**本文篇幅有点长,请作好心里准备!!! 同时,也吐个槽,本文看似内容简单的一B,但也花了笔者几个小时来准备示例以及写作,写技术文章真心伤不起 珍爱生命,远离程序!!! **
还是回到我们的正题,开始我们今天的系列教程:《一步一步创建ASP.NET MVC5程序Repository+Autofac+Automapper+SqlSugar》
本文知识要点

  • 用户注册/登录功能设计与实现
设计用户表
这个表呢,Rector已经为大家准备好了,mysql表结构如下:
SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for ts_user -- ---------------------------- DROP TABLE IF EXISTS `tb_user`; CREATE TABLE `tb_user`( `Id` int(10) NOT NULL AUTO_INCREMENT, `LoginName` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ‘‘ COMMENT ‘登录名‘, `Password` varchar(150) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ‘‘ COMMENT ‘密码‘, `DisplayName` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT ‘‘ COMMENT ‘显示名称‘, `RealName` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT ‘‘ COMMENT ‘真实姓名‘, `EmailAddress` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT ‘‘ COMMENT ‘电子邮箱‘, `Avatar` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT ‘‘ COMMENT ‘用户头像‘, `Status` int(2) NOT NULL DEFAULT 1 COMMENT ‘用户的状态,0:禁用,1:正常‘, `Telephone` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT ‘‘ COMMENT ‘手机号码‘, `Qq` varchar(15) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT ‘‘, `WebsiteUrl` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT ‘‘, `CreatedOn` datetime(0) NULL DEFAULT NULL COMMENT ‘用户创建时间‘, `CreatedIp` varchar(24) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT ‘‘ COMMENT ‘创建用户时的IP地址‘, `LoginCount` int(8) NULL DEFAULT 0 COMMENT ‘登录次数累加器‘, `LatestLoginDate` datetime(0) NULL DEFAULT NULL COMMENT ‘最近一次登录时间‘, `LatestLoginIp` varchar(24) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT ‘‘ COMMENT ‘最近一次登录时的IP地址‘, `ModifiedOn` datetime(0) NULL DEFAULT NULL COMMENT ‘最近修改时间‘, `Type` int(2) NULL DEFAULT 0 COMMENT ‘用户类型[-1:超级管理员,0:一般用户]‘, PRIMARY KEY (`Id`) USING BTREE, UNIQUE INDEX `IX_LoginName`(`LoginName`) USING BTREE, UNIQUE INDEX `IX_EmailAddress`(`EmailAddress`) USING BTREE, INDEX `IX_CreatedOn`(`CreatedOn`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 0 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; SET FOREIGN_KEY_CHECKS = 1;

请直接复制以上MySQL脚本,然后到对应数据执行即可,当然你也可以在这个版本的源码里面找到。 这个表就不准备提前写入示例数据了,一会我们用注册功能来写入数据。
创建领域实体和视图实体
在项目 【TsBlog.Domain】中的Entities文件夹中创建 User.cs 实体类:
using SqlSugar; using System; namespace TsBlog.Domain.Entities { [SugarTable(" tb_user" )] public class User { [SugarColumn(IsIdentity = true, IsPrimaryKey = true)] public int Id { get; set; } public string LoginName { get; set; } public string Password { get; set; } public string RealName { get; set; } public string EmailAddress { get; set; } public string Avatar { get; set; } public int Status { get; set; } public string Telephone { get; set; } public string Qq { get; set; } public string WebsiteUrl { get; set; } public DateTime CreatedOn { get; set; } public string CreatedIp { get; set; } public int LoginCount { get; set; } public DateTime? LatestLoginDate { get; set; } public string LatestLoginIp { get; set; } public DateTime? ModifiedOn { get; set; } public int Type { get; set; } } }

再在项目【TsBlog.ViewModel】中创建 User 的文件夹,并创建以下几个视图实体类
LoginViewModel.cs
using System.ComponentModel.DataAnnotations; namespace TsBlog.ViewModel.User { /// < summary> /// 用户登录视图实体 /// < /summary> public class LoginViewModel { [Required(ErrorMessage = " 请输入用户" )] [Display(Name = " 用户名" )] public string UserName { get; set; } [Required(ErrorMessage = " 请输入密码" )] [Display(Name = " 密码" )] [DataType(DataType.Password)] public string Password { get; set; } } }

RegisterViewModel.cs
using System.ComponentModel.DataAnnotations; namespace TsBlog.ViewModel.User { /// < summary> /// 用户注册视图实体 /// < /summary> public class RegisterViewModel { [Required(ErrorMessage = " 请输入用户名" )] [Display(Name = " 用户名" )] public string UserName { get; set; } [Required(ErrorMessage = " 请输入密码" )] [Display(Name = " 密码" )] [DataType(DataType.Password), MaxLength(20, ErrorMessage = " 密码最大长度为20个字符" ), MinLength(6, ErrorMessage = " 密码最小长度为6个字符" )] public string Password { get; set; }[Required(ErrorMessage = " 请输入确认密码" )] [Display(Name = " 确认密码" )] [DataType(DataType.Password), Compare(" Password" , ErrorMessage = " 两次密码不一致" )] public string ConfirmPassword { get; set; } } }

UserViewModel.cs:
using System; namespace TsBlog.ViewModel.User { /// < summary> /// 与领域用户实体对应的用户视图实体 /// < /summary> public class UserViewModel { public int Id { get; set; } public string LoginName { get; set; } public string Password { get; set; } public string RealName { get; set; } public string EmailAddress { get; set; } public string Avatar { get; set; } public int Status { get; set; } public string Telephone { get; set; } public string Qq { get; set; } public string WebsiteUrl { get; set; } public DateTime CreatedOn { get; set; } public string CreatedIp { get; set; } public int LoginCount { get; set; } public DateTime? LatestLoginDate { get; set; } public string LatestLoginIp { get; set; } public DateTime? ModifiedOn { get; set; } public int Type { get; set; } } }

仓储层
在项目【TsBlog.Repositories】中创建 IUserRepository.cs 以及其实现类 UserRepository.cs
IUserRepository.cs:
using TsBlog.Domain.Entities; namespace TsBlog.Repositories { public interface IUserRepository : IRepository< User> {} }

UserRepository.cs:
using TsBlog.Domain.Entities; namespace TsBlog.Repositories { public class UserRepository : GenericRepository< User> , IUserRepository {} }

服务层
在项目【TsBlog.Services】中创建 IUserService.cs 以及其实现类 UserService.cs
IUserService.cs:
using TsBlog.Domain.Entities; namespace TsBlog.Services { public interface IUserService : IService< User> { User FindByLoginName(string loginName); } }

UserService.cs:
using TsBlog.Domain.Entities; using TsBlog.Repositories; namespace TsBlog.Services { public class UserService : GenericService< User> , IUserService { private readonly IUserRepository _repository; public UserService(IUserRepository repository) : base(repository) { _repository = repository; }public User FindByLoginName(string loginName) { return _repository.FindByClause(x => x.LoginName == loginName); } } }

创建加密类
在解决方案文件夹【1.Libraries】中创建一个新的项目,取名为【TsBlog.Core】,在此项目中先创建一个名为 Security的文件夹,再创建一个加密类 Encryptor.cs
using System.Security.Cryptography; using System.Text; namespace TsBlog.Core.Security { /// < summary> /// 加密静态类 /// < /summary> public static class Encryptor { //MD5加密一个字符串 public static string Md5Hash(string text) { MD5 md5 = new MD5CryptoServiceProvider(); md5.ComputeHash(Encoding.ASCII.GetBytes(text)); var result = md5.Hash; var strBuilder = new StringBuilder(); foreach (var t in result) { strBuilder.Append(t.ToString(" x2" )); }return strBuilder.ToString(); } } }

在用户注册或者登录时,我们将使用这个MD5加密用户的密码,并将其保存到数据库中(数据库中保存明文的密码是非常危险的,特别是在重要的安全级别很高的项目中,千(不)万(信)别(你)这(试)样(一)做(下)!!!)。
创建控制器
在项目【TsBlog.Frontend】中创建控制器 AccountController.cs,并添加如下代码:
AccountController.cs
using System; using System.Web.Mvc; using TsBlog.Core.Security; using TsBlog.Domain.Entities; using TsBlog.Services; using TsBlog.ViewModel.User; namespace TsBlog.Frontend.Controllers { /// < summary> /// 用户中心控制器 /// < /summary> public class AccountController : Controller { /// < summary> /// 用户服务接口 /// < /summary> private readonly IUserService _userService; public AccountController(IUserService userService) { _userService = userService; }/// < summary> /// 登录页面 /// < /summary> /// < returns> < /returns> public ActionResult Login() { return View(); }/// < summary> /// 提交登录请求 /// < /summary> /// < param name=" model" > < /param> /// < returns> < /returns> [HttpPost, ValidateAntiForgeryToken, AllowAnonymous] public ActionResult Login(LoginViewModel model) { //如果视图模型中的属性没有验证通过,则返回到登录页面,要求用户重新填写 if (!ModelState.IsValid) { return View(model); }//根据用户登录名查询指定用户实体 var user = _userService.FindByLoginName(model.UserName.Trim()); //如果用户不存在,则携带错误消息并返回登录页面 if (user == null) { ModelState.AddModelError(" error_message" , " 用户不存在" ); return View(model); }//如果密码不匹配,则携带错误消息并返回登录页面 if (user.Password != Encryptor.Md5Hash(model.Password.Trim())) { ModelState.AddModelError(" error_message" , " 密码错误,请重新登录" ); return View(model); }//并用户实体保存到Session中 Session[" user_account" ] = user; //跳转到首页 return RedirectToAction(" index" , " home" ); }/// < summary> /// 注册页面 /// < /summary> /// < returns> < /returns> public ActionResult Register() { return View(); }/// < summary> /// 提交注册请求 /// < /summary> /// < param name=" model" > < /param> /// < returns> < /returns> [HttpPost, ValidateAntiForgeryToken, AllowAnonymous] public ActionResult Register(RegisterViewModel model) { //如果视图模型中的属性没有验证通过,则返回到注册页面,要求用户重新填写 if (!ModelState.IsValid) { return View(model); }//创建一个用户实体 var user = new User { LoginName = model.UserName, Password = Encryptor.Md5Hash(model.Password.Trim()), CreatedOn = DateTime.Now //由于是示例教程,所以其他字段不作填充了 }; //将用户实体对象写入数据库中 var ret = _userService.Insert(user); if (ret < = 0) { //如果注册失败,则携带错误消息并返回注册页面 ModelState.AddModelError(" error_message" , " 注册失败" ); return View(model); } //如果注册成功,则跳转到登录页面 return RedirectToAction(" login" ); } } }

添加必要JS库
由于之前我们将项目中的多余的JS库全部移除掉了,所以现在我们重新安装一下我们项目中将要到的一些JS库,包括:jQuery,Bootstrap等,都使用Nuget来安装,方便统一管理和升级。
安装jQuery:
一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar]

文章图片

安装Bootstrap:
一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar]

文章图片

安装jquery.validate.bootstrap:
一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar]

文章图片

安装完成后的JS库文件夹:
一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar]

文章图片

完成注册页面
在 [Views/Account]文件夹中创建注册页面视图 register.cshtml
@model TsBlog.ViewModel.User.RegisterViewModel @{ Layout = null; } < !DOCTYPE html> < html> < head> < meta name=" viewport" content=" width=device-width" /> < title> 用户注册< /title> < style type=" text/css" > * { box-sizing: border-box; } body { box-sizing: border-box; margin: 0; padding: 0; color: #333; } .account-container { position: absolute; margin: auto; top: 0; right: 0; bottom: 0; left: 0; width: 400px; height: 480px; background-color: #fff; /*border-radius: 3px; */ box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14), 0 3px 1px -2px rgba(0,0,0,0.12), 0 1px 5px 0 rgba(0,0,0,0.2); }.account-signin-container { margin-top: 15px; } .account-signin-container h1 { font-size: 20px; border-bottom: 2px solid #f7f7f7; margin: 0 0 15px; padding-bottom: 10px; padding-left: 15px; letter-spacing: 0.1em; } .account-form { padding: 15px; } .account-form .form-group { width: 100%; margin-bottom: 15px; } .account-form .form-group label { width: 100%; display: block; } .account-form .form-group input { border: 1px solid #ccc; line-height: 32px; font-size: 16px; padding: 2px 0px; padding-left: 5px; display: block; width: 100%; margin-top: 5px; } .account-form #btn_register { border: 0; background: #3b78e7; color: #fff; font-size: 18px; font-weight: bold; padding: 8px 25px; cursor: pointer; margin-top: 15px; display: inline-block; box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14), 0 3px 1px -2px rgba(0,0,0,0.12), 0 1px 5px 0 rgba(0,0,0,0.2); border-radius: 3px; min-width: 100px; text-align: center; } .account-form #btn_register:hover { background: #4885F3; } span.error { color: #f00; } .btn-login { float: right; display: block; margin-top: 25px; color: #4885f3; }@@media(max-width:500px) { .account-container { width: 100%; height: 100vh; } } < /style> < /head> < body> < div class=" account-container" > < div class=" account-modal-container" > < div class=" modal" > < /div> < div class=" load-bar-container" > < div class=" load-bar" > < div class=" bar" > < /div> < div class=" bar" > < /div> < div class=" bar" > < /div> < /div> < /div> < div class=" account-signin-container" > < h1> 用户注册< /h1> @using (Html.BeginForm(" register" , " account" , FormMethod.Post, new { @class = " account-form" , role = " form" })) { @Html.ValidationMessage(" error_message" , new { @class = " error" }) @Html.AntiForgeryToken() < div class=" form-group" > < label> < span> 登录名:< /span> @Html.TextBoxFor(m => m.UserName, new { placeholder = " 请输入登录名" }) @Html.ValidationMessageFor(m => m.UserName, " " , new { @class = " error" }) < /label> < /div> < div class=" form-group" > < label> < span> 密码:< /span> @Html.PasswordFor(m => m.Password, new { placeholder = " 请输入密码" }) @Html.ValidationMessageFor(m => m.Password, " " , new { @class = " error" }) < /label> < /div> < div class=" form-group" > < label> < span> 确认密码:< /span> @Html.PasswordFor(m => m.ConfirmPassword, new { placeholder = " 请输入确认密码" }) @Html.ValidationMessageFor(m => m.ConfirmPassword, " " , new { @class = " error" }) < /label> < /div> < div class=" form-group" > < button id=" btn_register" type=" submit" > 注 册< /button> < a class=" btn-login" href=https://www.songbingjia.com/android/" ~/account/login" > 登录< /a> < /div> }< /div> < /div> < /div> < script src=" ~/Scripts/jquery-3.2.1.min.js" > < /script> < script src=" ~/Scripts/jquery.validate.min.js" > < /script> < script src=" ~/Scripts/jquery.validate.unobtrusive.min.js" > < /script> < /body> < /html>

再在当前文件夹下创建 login.cshtml 视图文件用作登录页面:
@model TsBlog.ViewModel.User.LoginViewModel @{ Layout = null; } < !DOCTYPE html> < html> < head> < meta name=" viewport" content=" width=device-width" /> < title> 用户登录< /title> < style type=" text/css" > * { box-sizing: border-box; } body { box-sizing: border-box; margin: 0; padding: 0; color: #333; }.account-container { position: absolute; margin: auto; top: 0; right: 0; bottom: 0; left: 0; width: 400px; height: 450px; background-color: #fff; /*border-radius: 3px; */ box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14), 0 3px 1px -2px rgba(0,0,0,0.12), 0 1px 5px 0 rgba(0,0,0,0.2); }.account-signin-container { margin-top: 15px; } .account-signin-container h1 { font-size: 20px; border-bottom: 2px solid #f7f7f7; margin: 0 0 15px; padding-bottom: 10px; padding-left: 15px; letter-spacing: 0.1em; } .account-form { padding: 15px; } .account-form .form-group { width: 100%; margin-bottom: 15px; } .account-form .form-group label { width: 100%; display: block; } .account-form .form-group input { border: 1px solid #ccc; line-height: 32px; font-size: 16px; padding: 2px 0px; padding-left: 5px; display: block; width: 100%; margin-top: 5px; } .account-form #btn_login { border: 0; background: #3b78e7; color: #fff; font-size: 18px; font-weight: bold; padding: 8px 25px; cursor: pointer; margin-top: 15px; display: inline-block; box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14), 0 3px 1px -2px rgba(0,0,0,0.12), 0 1px 5px 0 rgba(0,0,0,0.2); border-radius: 3px; min-width: 100px; text-align: center; } .account-form #btn_login:hover { background: #4885F3; } span.error { color: #f00; } .btn-register { float: right; display: block; margin-top: 25px; color: #4885f3; }@@media(max-width:500px) { .account-container { width: 100%; height: 100vh; } } < /style> < /head> < body> < div class=" account-container" > < div class=" account-modal-container" > < div class=" modal" > < /div> < div class=" load-bar-container" > < div class=" load-bar" > < div class=" bar" > < /div> < div class=" bar" > < /div> < div class=" bar" > < /div> < /div> < /div> < div class=" account-signin-container" > < h1> 用户登录< /h1> @using (Html.BeginForm(" login" , " account" , FormMethod.Post, new { @class = " account-form" , role = " form" })) { @Html.ValidationMessage(" error_message" , new { @class = " error" }) @Html.AntiForgeryToken() < div class=" form-group" > < label> < span> 登录名:< /span> @Html.TextBoxFor(m => m.UserName, new { placeholder = " 请输入登录名" }) @Html.ValidationMessageFor(m => m.UserName, " " , new { @class = " error" }) < /label> < /div> < div class=" form-group" > < label> < span> 密码:< /span> @Html.PasswordFor(m => m.Password, new { placeholder = " 请输入密码" }) @Html.ValidationMessageFor(m => m.Password, " " , new { @class = " error" }) < /label> < /div> < div class=" form-group" > < button id=" btn_login" type=" submit" > 登 录< /button> < a class=" btn-register" href=https://www.songbingjia.com/android/" ~/account/register" > 注册账号< /a> < /div> }< /div> < /div> < /div> < script src=" ~/Scripts/jquery-3.2.1.min.js" > < /script> < script src=" ~/Scripts/jquery.validate.min.js" > < /script> < script src=" ~/Scripts/jquery.validate.unobtrusive.min.js" > < /script> < script src=" ~/res/assets/notie/notie.min.js" > < /script> < /body> < /html>

这两个页面均是响应式的布局,可适应不同设备。
好了,关于注册和登录的逻辑以及页面都完成了,那么运行项目,打开注册页面:http://localhost:54739/account/register,具体的注册请自行体验:
一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar]

文章图片

注册成功后,系统将带你到登录页面:
一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar]

文章图片

具体功能也请自行体验。
以上,我们只完成了注册和登录的基本功能,接下来我们来体验一下简单的权限访问,在本期教程之前,我们的: http://localhost:54739/home/index 以及 http://localhost:54739/home/post 是可以直接访问的,现在我们给这两个页面添加访问权限,即只有登录后才能访问,修改 HomeController.cs 如下:
using System.Web.Mvc; using TsBlog.AutoMapperConfig; using TsBlog.Services; namespace TsBlog.Frontend.Controllers { public class HomeController : Controller { private readonly IPostService _postService; public HomeController(IPostService postService) { _postService = postService; } public ActionResult Index() { //如果未登录,则跳转到登录页面 if (Session[" user_account" ] == null) { return RedirectToAction(" login" , " account" ); } return View(); }public ActionResult Post() { //如果未登录,则跳转到登录页面 if (Session[" user_account" ] == null) { return RedirectToAction(" login" , " account" ); }var post = _postService.FindById(1).ToModel(); return View(post); } } }

重新编译项目,按F5运行,再打开地址:http://localhost:54739/home/index ,发生了什么情况? 是不是被重定向到了登录页面,要求你登录? 这就对了,输入你刚才注册的用户名和密码,登录后,系统会重新带你到:http://localhost:54739/home/index 页面。
OK,今天这期的关于用户注册和登录功能就介绍到这里,本期只实现了简单的功能,在后续的教程中将重构和封装相应的功能代码,敬请期待。。。
如果你喜欢Rector的本系列文章,请为我点个大大的赞。
看完教程如果觉得还不过瘾的,遇到问题的,想“勾对”的,欢迎加入图享网官方QQ群:483350228。有什么,你懂的。。。
谢谢你的耐心阅读,未完待续,我们下期再见……
本期源码托管,请至首发地址获取-- 《一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](八)》
数据库脚本文件请到目录下获取:TsBlog\document\scripts\mysql\v1.8\
本文来源自 图享网 《一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](八)》

    推荐阅读