俗话说,磨刀不费砍柴工。为了更方便的进行项目管理,咱们先将我的网站项目配置一下,知足如下2个目标:html
有了以上的配置,咱们能够不用每次拉取和同步咱们的程序到Github中,也不用每次在本地发布,拷贝服务器,咱们只用在VS2017中简单的一键同步到Github或网站服务器。这样咱们的开发效率有了很大的提升,也方便线上验证咱们的程序代码。前端
选择 工具-->扩展和更新,搜索GitHub,安装GitHub的VS插件git
安装完插件,打开视图-->团队资源管理器,咱们能够看到Git插件菜单。经过菜单咱们能够新建Git存储库,能够提交修改的代码,并一键同步提交后的代码到本身的GitHub项目中。bootstrap
再打开GitHub,能够看咱们的代码已经同步了,是否是很方便?浏览器
要VS支持FTP发布,首先要将网站服务器配置成FTP服务器。安全
Server2008添加新的角色,选中文件服务并安装新角色:前端框架
再次选中已安装的IIS服务,增长FTP服务器相关的角色:服务器
接着,在IIS网站右键选择“添加FTP站点”,选择FTP文件物理路径和添加站点名称:mvc
端口默认21,不用选择SSL证书,身份验证这里选择基本验证(为了必定的安全性,不要勾选匿名),受权访问里,指定administrator才能访问FTP站点,并具备读取和写入的权限;app
完成后,咱们建好的FTP就自动启动了,这时浏览器中输入ftp://localhost,输入用户名和密码,就能够访问对应的文件目录了。固然,咱们外网仍是没法访问,为何呢?相信你们看过上一篇,应该知道是防火墙的缘由,咱们按照上一篇的配置,增长FTP 21端口的容许入站规则,这样咱们外网就经过FTP访问网站发布目录。
配置完外网服务器,咱们来配置一下本地VS2017,右键项目-->发布,选择FTP发布,选项配置以下:
这样咱们就已经配置好本地一键发布站点到远程服务器了。之后直接点发布按钮,就能够看到自动将生成的发布文件,同步到网站服务器:
准备工做作完,浏览器输入网站服务器IP,能够看到能够正常访问,可是.net core mvc帮咱们自动生成的界面,不必定符合咱们的需求,那仍是本身找一个前端的UI框架,替换一下既有界面。这里我选择的是 AdminLTE ,这是一个基于 bootstrap 的轻量级后台模板,相关的资料你们能够去官网研究一下。
咱们把下载的文件解压缩到wwwroot/lib目录下,第一步先重构一下登陆的界面:
1 @model LoginViewModel 2 3 @{ 4 Layout = null; 5 ViewData["Title"] = "登陆"; 6 } 7 8 <!DOCTYPE html> 9 <html> 10 <head> 11 <meta charset="utf-8" /> 12 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 13 <title>@ViewData["Title"] - LanceL0t</title> 14 15 @await Html.PartialAsync("_SiteCssPartial") 16 </head> 17 <body class="hold-transition login-page"> 18 <div class="login-box"> 19 <div class="login-box-body"> 20 <p class="login-box-msg">欢迎,由此登陆</p> 21 <form asp-route-returnurl="@ViewData["ReturnUrl"]" method="post"> 22 <div asp-validation-summary="All" class="text-danger"></div> 23 <div class="form-group has-feedback"> 24 <input asp-for="Email" class="form-control" placeholder="邮箱"> 25 <span class="glyphicon glyphicon-envelope form-control-feedback"></span> 26 </div> 27 <div class="form-group has-feedback"> 28 <input asp-for="Password" class="form-control" placeholder="密码"> 29 <span class="glyphicon glyphicon-lock form-control-feedback"></span> 30 </div> 31 <div class="row"> 32 <div class="col-xs-8"> 33 <div class="checkbox icheck"> 34 <label asp-for="RememberMe"> 35 <input asp-for="RememberMe"> @Html.DisplayNameFor(m => m.RememberMe) 36 </label> 37 </div> 38 </div> 39 <div class="col-xs-4"> 40 <button type="submit" class="btn btn-primary btn-block btn-flat">登陆</button> 41 </div> 42 </div> 43 </form> 44 <div class="social-auth-links text-center"> 45 <p>- 或者 -</p> 46 <a href="#" class="btn btn-block btn-social btn-facebook btn-flat"> 47 <i class="fa fa-facebook"></i> Sign in using 48 Facebook 49 </a> 50 <a href="#" class="btn btn-block btn-social btn-google btn-flat"> 51 <i class="fa fa-google-plus"></i> Sign in using 52 Google+ 53 </a> 54 </div> 55 <a asp-action="ForgotPassword">忘记密码</a><br> 56 <a asp-action="Register" asp-route-returnurl="@ViewData["ReturnUrl"]" class="text-center">当即注册</a> 57 </div> 58 </div> 59 </body> 60 </html> 61 62 @await Html.PartialAsync("_SiteScriptsPartial") 63 @await Html.PartialAsync("_ValidationScriptsPartial")
接着第二步,优化一下以前的新用户注册界面:
1 @model RegisterViewModel 2 3 @{ 4 Layout = null; 5 ViewData["Title"] = "注册"; 6 } 7 8 <!DOCTYPE html> 9 <html> 10 <head> 11 <meta charset="utf-8" /> 12 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 13 <title>@ViewData["Title"] - LanceL0t</title> 14 15 @await Html.PartialAsync("_SiteCssPartial") 16 </head> 17 <body class="hold-transition login-page"> 18 <div class="login-box"> 19 <div class="login-box-body"> 20 <p class="login-box-msg">欢迎,注册新用户</p> 21 <form asp-route-returnurl="@ViewData["ReturnUrl"]" method="post"> 22 <div asp-validation-summary="All" class="text-danger"></div> 23 <div class="form-group has-feedback"> 24 <input asp-for="Email" class="form-control" placeholder="请输入邮箱"> 25 <span class="glyphicon glyphicon-envelope form-control-feedback"></span> 26 </div> 27 <div class="form-group has-feedback"> 28 <input asp-for="Password" class="form-control" placeholder="请输入密码"> 29 <span class="glyphicon glyphicon-lock form-control-feedback"></span> 30 31 </div> 32 <div class="form-group has-feedback"> 33 <input asp-for="ConfirmPassword" class="form-control" placeholder="请确认密码"> 34 <span class="glyphicon glyphicon-lock form-control-feedback"></span> 35 </div> 36 <div class="row"> 37 <div class="col-xs-8"> 38 <div class="checkbox icheck"> 39 <label asp-for="IsAgree"> 40 <input asp-for="IsAgree"> 阅读并接受《<a href="#">用户协议</a>》 41 </label> 42 </div> 43 </div> 44 <div class="col-xs-4"> 45 <button type="submit" class="btn btn-primary btn-block btn-flat">注册</button> 46 </div> 47 </div> 48 </form> 49 <div class="social-auth-links text-center"> 50 <p>- 或者 -</p> 51 <a href="#" class="btn btn-block btn-social btn-facebook btn-flat"> 52 <i class="fa fa-facebook"></i> Sign in using 53 Facebook 54 </a> 55 <a href="#" class="btn btn-block btn-social btn-google btn-flat"> 56 <i class="fa fa-google-plus"></i> Sign in using 57 Google+ 58 </a> 59 </div> 60 <a asp-controller="Account" asp-action="Login">已有帐号</a><br> 61 </div> 62 </div> 63 </body> 64 </html> 65 66 @await Html.PartialAsync("_SiteScriptsPartial") 67 @await Html.PartialAsync("_ValidationScriptsPartial")
这里的知识很简单,就不在祥述了,不过由于用的是.net core提供的identity用户管理和验证,有些我的遇到的问题,我仍是列出来,以避免再走弯路。
好比,新用户注册时,要保证用户已勾选“阅读并接受用户协议”。而MVC自己校验机制没有提供bool型必须为true的校验,这里咱们本身实现一个服务器端属性的校验,须要继承
ValidationAttribute和IClientModelValidator:
1 /// <summary> 2 /// 复选框必须选中验证 3 /// </summary> 4 [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)] 5 public sealed class MustBeTrueAttribute : ValidationAttribute, IClientModelValidator 6 { 7 //服务器端验证 8 public override bool IsValid(object value) 9 { 10 return value != null && (bool)value; 11 } 12 13 public void AddValidation(ClientModelValidationContext context) 14 { 15 MergeAttribute(context.Attributes, "data-val", "true"); 16 var errorMessage = FormatErrorMessage(context.ModelMetadata.GetDisplayName()); 17 MergeAttribute(context.Attributes, "data-val-mustbetrue", errorMessage); 18 } 19 20 private bool MergeAttribute( 21 IDictionary<string, string> attributes, 22 string key, 23 string value) 24 { 25 if (attributes.ContainsKey(key)) 26 { 27 return false; 28 } 29 attributes.Add(key, value); 30 return true; 31 } 32 }
再加上客户端的验证方法:
1 <script> 2 //必须复选框勾选验证 3 $.validator.addMethod("mustbetrue", 4 function (value, element, parameters) { 5 return value === "true"; 6 }); 7 8 $.validator.unobtrusive.adapters.add("mustbetrue", [], function (options) { 9 options.rules.mustbetrue = {}; 10 options.messages["mustbetrue"] = options.message; 11 }); 12 </script>
目前使用identity默认的错误描述是英文,这里咱们须要显示成中文,因此新增一个IdentityExtensions类,继承IdentityErrorDescriber,重写错误描述
1 public class IdentityExtensions : IdentityErrorDescriber 2 { 3 public override IdentityError PasswordRequiresNonAlphanumeric() 4 { 5 return new IdentityError 6 { 7 Code = nameof(PasswordRequiresNonAlphanumeric), 8 Description = "密码至少包含1位非数字字母的特殊字符" 9 }; 10 } 11 12 public override IdentityError PasswordRequiresDigit() 13 { 14 return new IdentityError 15 { 16 Code = nameof(PasswordRequiresDigit), 17 Description = "密码至少包含1位数字('0'-'9')" 18 }; 19 } 20 21 public override IdentityError PasswordRequiresLower() 22 { 23 return new IdentityError 24 { 25 Code = nameof(PasswordRequiresLower), 26 Description = "密码至少包含1位小写字符 ('a'-'z')" 27 }; 28 } 29 30 public override IdentityError PasswordRequiresUpper() 31 { 32 return new IdentityError 33 { 34 Code = nameof(PasswordRequiresUpper), 35 Description = "密码至少包含1位大写写字符 ('A'-'Z')" 36 }; 37 } 38 }
重写中文错误描述后,咱们还得在Startup.cs文件中的服务配置中注册:
1 public void ConfigureServices(IServiceCollection services) 2 { 3 services.AddDbContext<ApplicationDbContext>(options => 4 options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); 5 6 services.AddIdentity<ApplicationUser, IdentityRole>() 7 .AddEntityFrameworkStores<ApplicationDbContext>() 8 .AddDefaultTokenProviders() 9 .AddErrorDescriber<IdentityExtensions>(); 10 11 // Add application services. 12 services.AddTransient<IEmailSender, EmailSender>(); 13 14 services.AddMvc(); 15 }
登陆和注册新用户没有问题了,再来改造一下登陆后主页的布局,把_Layout布局视图分割成顶部区域、左侧导航菜单、内容区域、底部区域、右侧侧边栏,并用部分视图分别渲染:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 <title>@ViewData["Title"] - LanceL0t</title> 7 8 @await Html.PartialAsync("_SiteCssPartial") 9 </head> 10 <body class="hold-transition skin-blue sidebar-mini"> 11 <div class="wrapper"> 12 <!-- 顶部区域 --> 13 @await Html.PartialAsync("_LayoutHeaderPartial") 14 <!-- 导航栏 --> 15 @await Html.PartialAsync("_LayoutNavbarPartial") 16 <!-- 内容区域 --> 17 <div class="content-wrapper"> 18 <section class="content-header"> 19 <h1> 20 Dashboard 21 <small>Version 2.0</small> 22 </h1> 23 <ol class="breadcrumb"> 24 <li><a href="#"><i class="fa fa-dashboard"></i> 主页</a></li> 25 <li class="active">Dashboard</li> 26 </ol> 27 </section> 28 <section class="content"> 29 @RenderBody() 30 </section> 31 </div> 32 <!-- 底部区域 --> 33 @await Html.PartialAsync("_LayoutFooterPartial") 34 <!-- 侧边栏 --> 35 @await Html.PartialAsync("_LayoutSidebarPartial") 36 </div> 37 38 @await Html.PartialAsync("_SiteScriptsPartial") 39 @RenderSection("Scripts", required: false) 40 </body> 41 </html>
这样,咱们登陆和注册功能大致完成了,咱们看下效果: