1-UI,登陆界面布局
PS:使用的是metronic 框架,没有用过的可以自行百度。
1.1 metronic 放在wwwroot文件夹下面
1.2 metronic 中的 open sans 使用的是 谷歌的DNS,所以我们需要自己下载本地资源(使用nuget管理器下载,也可以用nuget控制台)。
1.3 创建Account控制器和视图 ,由于现在不支持在controller中直接右击生成视图文件,因此我们需要自己在Views文件下创建Account文件夹和Login.cshtml文件。
1.3.1 在Account 中创建布局页面Layout.cshtml
1 DOCTYPE html> 2 3 4 5 <html lang="en"> 6 7 8 <head> 9 <meta charset="utf-8" /> 10 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 11 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 12 <meta content="" name="description" /> 13 <meta content="" name="author" /> 14 <title>@ViewData["Title"] - NET Core Demotitle> 15 <environment names="Development"> 16 <link rel="stylesheet" href="~/css/font-open-sans.css" /> 17 <link href="~/metronic/assets/global/plugins/font-awesome/css/font-awesome.css" rel="stylesheet" type="text/css" /> 18 <link href="~/metronic/assets/global/plugins/bootstrap/css/bootstrap.css" rel="stylesheet" type="text/css" /> 19 <link href="~/metronic/assets/global/css/components.css" rel="stylesheet" id="style_components" type="text/css" /> 20 <link href="~/metronic/assets/pages/css/login.css" rel="stylesheet" type="text/css" /> 21 environment> 22 <environment names="Staging,Production"> 23 <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Open+Sans:400,300,600,700&subset=all" 24 asp-fallback-href="~/css/font-open-sans.min.css" 25 asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" /> 26 <link href="~/metronic/assets/global/plugins/font-awesome/css/font-awesome.css" rel="stylesheet" type="text/css" /> 27 <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/css/bootstrap.min.css" 28 asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css" 29 asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" /> 30 <link href="~/metronic/assets/global/css/components.min.css" rel="stylesheet" id="style_components" type="text/css" /> 31 <link href="~/metronic/assets/pages/css/login.min.css" rel="stylesheet" type="text/css" /> 32 environment> 33 @RenderSection("css", required: false) 34 @Html.ApplicationInsightsJavaScript(TelemetryConfiguration) 35 head> 36 <body class="login"> 37 <div class="logo"> 38 <a href="index.html"> 39 <img src="~/metronic/assets/pages/img/logo-big.png" alt="" /> 40 a> 41 div> 42 <div class="content"> 43 @RenderBody() 44 div> 45 <div class="copyright">2014 © Metronic. Admin Dashboard Template.div> 46 50 <script src="~/metronic/assets/global/plugins/jquery.min.js" type="text/javascript">script> 51 <script src="~/metronic/assets/global/plugins/bootstrap/js/bootstrap.min.js" type="text/javascript">script> 52 @*<script src="~/metronic/assets/global/plugins/js.cookie.min.js" type="text/javascript">script>*@ 53 <script src="~/metronic/assets/global/plugins/jquery-validation/js/jquery.validate.min.js" type="text/javascript">script> 54 @*<script src="~/metronic/assets/global/plugins/jquery-validation/js/additional-methods.min.js" type="text/javascript">script>*@ 55 <script src="~/metronic/assets/global/scripts/app.min.js" type="text/javascript">script> 56 57 @RenderSection("scripts", required: false) 58 body> 59 html>
1.3.2 login登陆页面
1 <form class="login-form" asp-action="Login" asp-controller="Account" method="post"> 2 @Html.AntiForgeryToken() 3 <h3 class="form-title font-green">登录h3> 4 <div class="alert alert-danger display-hide"> 5 <button class="close" data-close="alert">button> 6 <span> 请输入用户名或密码. span> 7 div> 8 @if (ViewBag.IsInvalid) 9 { 10 <div class="alert alert-danger"> 11 <button class="close" data-close="alert">button> 12 <span> @ViewBag.ErrorMsg. span> 13 div> 14 } 15 <div class="form-group"> 16 17 <label class="control-label visible-ie8 visible-ie9">用户名label> 18 <input class="form-control form-control-solid placeholder-no-fix" type="text" autocomplete="off" placeholder="用户名" name="username" /> 19 div> 20 <div class="form-group"> 21 <label class="control-label visible-ie8 visible-ie9">密码label> 22 <input class="form-control form-control-solid placeholder-no-fix" type="password" autocomplete="off" placeholder="密码" name="password" /> 23 div> 24 <div class="form-actions"> 25 <button type="submit" class="btn green uppercase">登录button> 26 <label class="rememberme check"> 27 <input type="checkbox" name="remember" value="1" />记住密码 28 label> 29 <a asp-area="" asp-controller="Account" asp-action="ForgetPassword" id="forget-password" class="forget-password">忘记密码?a> 30 div> 31 <input hidden id="returnUrl" name="returnUrl" value="@ViewBag.ReturnUrl" /> 32 form> 33 @section scripts{ 34 <environment names="Development"> 35 <script src="~/js/account/login.js" type="text/javascript">script> 36 environment> 37 <environment names="Staging,Production"> 38 <script src="~/js/account/login.min.js" type="text/javascript">script> 39 environment> 40 }
1.3.3 配置文件压缩机制bundleconfig.json (压缩文件只有当你发布系统的时候才会生成,DEBUG的时候不会生成)。
2- 登录代码实现,依赖注册
2.1 GR.Core中创建IRepository通用仓储接口(该代码来自ABP的实现,我自己有修改)。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Linq.Expressions; 5 using System.Threading.Tasks; 6 using GR.Core.Domain; 7 8 namespace GR.Core.Data 9 { 10 ///11 /// Repository 12 /// 13 public partial interface IRepository :IRepository int> where TEntity : BaseEntity 14 { 15 16 } 17 18 /// 19 /// This interface is implemented by all repositories to ensure implementation of fixed methods. 20 /// 21 /// 22 /// 参考ABP实现 https://github.com/aspnetboilerplate 23 /// 24 /// Main Entity type this repository works on 25 /// Primary key type of the entity 26 public interface IRepository where TEntity : BaseEntity 27 { 28 #region Select/Get/Query 29 30 /// 31 /// Used to get a IQueryable that is used to retrieve entities from entire table. 32 /// attribute must be used to be able to call this method since this method 33 /// returns IQueryable and it requires open database connection to use it. 34 /// 35 /// IQueryable to be used to select entities from database 36 IQueryable GetAll(); 37 38 /// 39 /// Used to get all entities. 40 /// 41 /// List of all entities 42 List GetAllList(); 43 44 /// 45 /// Used to get all entities. 46 /// 47 /// List of all entities 48 Task > GetAllListAsync(); 49 50 ///
51 /// Used to get all entities based on given . 52 /// 53 /// A condition to filter entities 54 /// List of all entities 55 List GetAllList(Expression bool>> predicate); 56 57 /// 58 /// Used to get all entities based on given . 59 /// 60 /// A condition to filter entities 61 /// List of all entities 62 Task > GetAllListAsync(Expression
bool>> predicate); 63 64 /// 65 /// Used to run a query over entire entities. 66 /// attribute is not always necessary (as opposite to ) 67 /// if finishes IQueryable with ToList, FirstOrDefault etc.. 68 /// 69 /// Type of return value of this method 70 /// This method is used to query over entities 71 /// Query result 72 T Query (Func , T> queryMethod); 73 74 /// 75 /// Gets an entity with given primary key. 76 /// 77 /// Primary key of the entity to get 78 /// Entity 79 TEntity Get(TPrimaryKey id); 80 81 /// 82 /// Gets an entity with given primary key. 83 /// 84 /// Primary key of the entity to get 85 /// Entity 86 Task GetAsync(TPrimaryKey id); 87 88 /// 89 /// Gets exactly one entity with given predicate. 90 /// Throws exception if no entity or more than one entity. 91 /// 92 /// Entity 93 TEntity Single(Expression bool>> predicate); 94 95 /// 96 /// Gets exactly one entity with given predicate. 97 /// Throws exception if no entity or more than one entity. 98 /// 99 /// Entity 100 Task SingleAsync(Expression bool>> predicate); 101 102 /// 103 /// Gets an entity with given primary key or null if not found. 104 /// 105 /// Primary key of the entity to get 106 /// Entity or null 107 TEntity FirstOrDefault(TPrimaryKey id); 108 109 /// 110 /// Gets an entity with given primary key or null if not found. 111 /// 112 /// Primary key of the entity to get 113 /// Entity or null 114 Task FirstOrDefaultAsync(TPrimaryKey id); 115 116 /// 117 /// Gets an entity with given given predicate or null if not found. 118 /// 119 /// Predicate to filter entities 120 TEntity FirstOrDefault(Expression bool>> predicate); 121 122 /// 123 /// Gets an entity with given given predicate or null if not found. 124 /// 125 /// Predicate to filter entities 126 Task FirstOrDefaultAsync(Expression bool>> predicate); 127 128 /// 129 /// Creates an entity with given primary key without database access. 130 /// 131 /// Primary key of the entity to load 132 /// Entity 133 TEntity Load(TPrimaryKey id); 134 135 #endregion 136 137 138 /// 139 /// Inserts a new entity. 140 /// 141 /// Inserted entity 142 int Insert(TEntity entity, bool IsCommit = true); 143 144 /// 145 /// Inserts a new entity. 146 /// 147 /// Inserted entity 148 Task<int> InsertAsync(TEntity entity, bool IsCommit = true); 149 150 /// 151 /// Inserts or updates given entity depending on Id's value. 152 /// 153 /// Entity 154 int InsertOrUpdate(TEntity entity, bool IsCommit = true); 155 156 /// 157 /// Inserts or updates given entity depending on Id's value. 158 /// 159 /// Entity 160 Task<int> InsertOrUpdateAsync(TEntity entity, bool IsCommit = true); 161 162 /// 163 /// Updates an existing entity. 164 /// 165 /// Entity 166 int Update(TEntity entity, bool IsCommit = true); 167 168 /// 169 /// Updates an existing entity. 170 /// 171 /// Entity 172 Task<int> UpdateAsync(TEntity entity, bool IsCommit = true); 173 174 175 /// 176 /// Deletes an entity. 177 /// 178 /// Entity to be deleted 179 int Delete(TEntity entity, bool IsCommit = true); 180 181 /// 182 /// Deletes an entity. 183 /// 184 /// Entity to be deleted 185 Task DeleteAsync(TEntity entity, bool IsCommit = true); 186 187 /// 188 /// Deletes an entity by primary key. 189 /// 190 /// Primary key of the entity 191 int Delete(TPrimaryKey id, bool IsCommit = true); 192 193 /// 194 /// Deletes an entity by primary key. 195 /// 196 /// Primary key of the entity 197 Task DeleteAsync(TPrimaryKey id, bool IsCommit = true); 198 199 /// 200 /// Deletes many entities by function. 201 /// Notice that: All entities fits to given predicate are retrieved and deleted. 202 /// This may cause major performance problems if there are too many entities with 203 /// given predicate. 204 /// 205 /// A condition to filter entities 206 void Delete(Expression bool>> predicate, bool IsCommit = true); 207 208 /// 209 /// Deletes many entities by function. 210 /// Notice that: All entities fits to given predicate are retrieved and deleted. 211 /// This may cause major performance problems if there are too many entities with 212 /// given predicate. 213 /// 214 /// A condition to filter entities 215 Task DeleteAsync(Expression bool>> predicate, bool IsCommit = true); 216 217 218 #region Aggregates 219 220 /// 221 /// Gets count of all entities in this repository. 222 /// 223 /// Count of entities 224 int Count(); 225 226 /// 227 /// Gets count of all entities in this repository. 228 /// 229 /// Count of entities 230 Task<int> CountAsync(); 231 232 /// 233 /// Gets count of all entities in this repository based on given . 234 /// 235 /// A method to filter count 236 /// Count of entities 237 int Count(Expression bool>> predicate); 238 239 /// 240 /// Gets count of all entities in this repository based on given . 241 /// 242 /// A method to filter count 243 /// Count of entities 244 Task<int> CountAsync(Expression bool>> predicate); 245 246 /// 247 /// Gets count of all entities in this repository (use if expected return value is greather than . 248 /// 249 /// Count of entities 250 long LongCount(); 251 252 /// 253 /// Gets count of all entities in this repository (use if expected return value is greather than . 254 /// 255 /// Count of entities 256 Task<long> LongCountAsync(); 257 258 /// 259 /// Gets count of all entities in this repository based on given 260 /// (use this overload if expected return value is greather than ). 261 /// 262 /// A method to filter count 263 /// Count of entities 264 long LongCount(Expression bool>> predicate); 265 266 /// 267 /// Gets count of all entities in this repository based on given 268 /// (use this overload if expected return value is greather than ). 269 /// 270 /// A method to filter count 271 /// Count of entities 272 Task<long> LongCountAsync(Expression bool>> predicate); 273 274 #endregion 275 } 276 }
2.2 GR.Data中创建EFRepository通用仓储实现(该代码来自ABP的实现,我自己有修改)。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Linq.Expressions; 5 using System.Threading.Tasks; 6 using GR.Core.Data; 7 using GR.Core.Domain; 8 using Microsoft.EntityFrameworkCore; 9 10 namespace GR.Data.Repository 11 { 12 ///13 /// 14 /// 15 /// 16 public class EfRepository : EfRepositoryBase int>, IRepository where TEntity : BaseEntity 17 { 18 public EfRepository(GRDbContext dbContext) : base(dbContext) 19 { } 20 } 21 22 /// 23 /// 通用仓储基类 24 /// 25 /// 26 /// 参考了 ABP 的 仓储基类 27 /// https://github.com/aspnetboilerplate 28 /// 29 /// 30 /// 31 /// 32 public abstract class EfRepositoryBase 33 where TDbContext : DbContext 34 where TEntity : BaseEntity 35 { 36 private readonly TDbContext _dbContext; 37 38 public EfRepositoryBase(TDbContext dbContext) 39 { 40 _dbContext = dbContext; 41 } 42 43 /// 44 /// Gets DbSet for given entity. 45 /// 46 public virtual DbSet Table 47 { 48 get 49 { 50 return _dbContext.Set (); 51 } 52 } 53 54 /// 55 /// Gets EF DbContext object. 56 /// 57 public virtual TDbContext DbContext 58 { 59 get { return _dbContext; } 60 } 61 62 public IQueryable GetAll() 63 { 64 return Table; 65 } 66 67 public TEntity FirstOrDefault(TPrimaryKey id) 68 { 69 return GetAll().FirstOrDefault(CreateEqualityExpressionForId(id)); 70 } 71 72 public List GetAllList() 73 { 74 return Table.ToList(); 75 } 76 77 public List GetAllList(Expression bool>> predicate) 78 { 79 return Table.Where(predicate).ToList(); 80 } 81 82 public async Task > GetAllListAsync() 83 { 84 return await GetAll().ToListAsync(); 85 } 86 87 public async Task
> GetAllListAsync(Expression
bool>> predicate) 88 { 89 return await GetAll().Where(predicate).ToListAsync(); 90 } 91 92 public T Query (Func , T> queryMethod) 93 { 94 return queryMethod(GetAll()); 95 } 96 97 public TEntity Get(TPrimaryKey id) 98 { 99 var entity = FirstOrDefault(id); 100 if (entity == null) 101 { 102 throw new ArgumentNullException("There is no such an entity with given primary key. Entity type: " + typeof(TEntity).FullName + ", primary key: " + id); 103 } 104 return entity; 105 } 106 107 public async Task GetAsync(TPrimaryKey id) 108 { 109 var entity = await FirstOrDefaultAsync(id); 110 if (entity == null) 111 { 112 throw new ArgumentNullException("There is no such an entity with given primary key. Entity type: " + typeof(TEntity).FullName + ", primary key: " + id); 113 } 114 115 return entity; 116 } 117 118 public TEntity Single(Expression bool>> predicate) 119 { 120 return GetAll().Single(predicate); 121 } 122 123 public async Task SingleAsync(Expression bool>> predicate) 124 { 125 return await GetAll().SingleAsync(predicate); 126 } 127 128 public async Task FirstOrDefaultAsync(TPrimaryKey id) 129 { 130 return await GetAll().FirstOrDefaultAsync(CreateEqualityExpressionForId(id)); 131 } 132 133 public async Task FirstOrDefaultAsync(Expression bool>> predicate) 134 { 135 return await GetAll().FirstOrDefaultAsync(predicate); 136 } 137 138 public int Insert(TEntity entity, bool IsCommit = true) 139 { 140 Table.Add(entity); 141 return IsCommit ? _dbContext.SaveChanges() : -1; 142 } 143 144 public Task<int> InsertAsync(TEntity entity, bool IsCommit = true) 145 { 146 Table.Add(entity); 147 return IsCommit ? Task.FromResult(_dbContext.SaveChanges()) : Task.FromResult(-1); 148 } 149 150 public int Update(TEntity entity, bool IsCommit = true) 151 { 152 AttachIfNot(entity); 153 _dbContext.Entry(entity).State = EntityState.Modified; 154 return IsCommit ? _dbContext.SaveChanges() : -1; 155 } 156 157 public Task<int> UpdateAsync(TEntity entity, bool IsCommit = true) 158 { 159 AttachIfNot(entity); 160 _dbContext.Entry(entity).State = EntityState.Modified; 161 return IsCommit ? Task.FromResult(_dbContext.SaveChanges()) : Task.FromResult(-1); 162 } 163 164 165 public int InsertOrUpdate(TEntity entity, bool IsCommit = true) 166 { 167 return entity.IsTransient() ? Insert(entity, IsCommit) : Update(entity, IsCommit); 168 } 169 170 public async Task<int> InsertOrUpdateAsync(TEntity entity, bool IsCommit = true) 171 { 172 return entity.IsTransient() ? await InsertAsync(entity, IsCommit) : await UpdateAsync(entity, IsCommit); 173 } 174 175 public int Delete(TEntity entity, bool IsCommit = true) 176 { 177 AttachIfNot(entity); 178 Table.Remove(entity); 179 return IsCommit ? _dbContext.SaveChanges() : -1; 180 } 181 182 public int Delete(TPrimaryKey id, bool IsCommit = true) 183 { 184 var entity = FirstOrDefault(id); 185 if (entity == null) 186 { 187 return 0; 188 } 189 return Delete(entity, IsCommit); 190 } 191 192 public Task DeleteAsync(TEntity entity, bool IsCommit = true) 193 { 194 return Task.FromResult(Delete(entity, IsCommit)); 195 } 196 197 public Task DeleteAsync(TPrimaryKey id, bool IsCommit = true) 198 { 199 return Task.FromResult(Delete(id, IsCommit)); 200 } 201 202 public void Delete(Expression bool>> predicate, bool IsCommit = true) 203 { 204 var entities = GetAll().Where(predicate).ToList(); 205 entities.ForEach(entity => 206 { 207 Delete(entity, IsCommit); 208 }); 209 } 210 211 212 public Task DeleteAsync(Expression bool>> predicate, bool IsCommit = true) 213 { 214 Delete(predicate, IsCommit); 215 return Task.FromResult(1); 216 } 217 public async Task<int> CountAsync() 218 { 219 return await GetAll().CountAsync(); 220 } 221 222 public async Task<int> CountAsync(Expression bool>> predicate) 223 { 224 return await GetAll().Where(predicate).CountAsync(); 225 } 226 227 public async Task<long> LongCountAsync() 228 { 229 return await GetAll().LongCountAsync(); 230 } 231 232 public async Task<long> LongCountAsync(Expression bool>> predicate) 233 { 234 return await GetAll().Where(predicate).LongCountAsync(); 235 } 236 237 protected static Expression bool>> CreateEqualityExpressionForId(TPrimaryKey id) 238 { 239 var lambdaParam = Expression.Parameter(typeof(TEntity)); 240 241 var lambdaBody = Expression.Equal( 242 Expression.PropertyOrField(lambdaParam, "Id"), 243 Expression.Constant(id, typeof(TPrimaryKey)) 244 ); 245 246 return Expression.Lambda bool>>(lambdaBody, lambdaParam); 247 } 248 249 protected void AttachIfNot(TEntity entity) 250 { 251 //if (!Table.Local.Contains(entity)) 252 //{ 253 // Table.Attach(entity); 254 //} 255 Table.Attach(entity); 256 } 257 258 public int Commit() 259 { 260 return _dbContext.SaveChanges(); 261 } 262 263 public async Task<int> CommitAsync() 264 { 265 return await _dbContext.SaveChangesAsync(); 266 } 267 268 public TEntity FirstOrDefault(Expression bool>> predicate) 269 { 270 return GetAll().FirstOrDefault(predicate); 271 } 272 273 public TEntity Load(TPrimaryKey id) 274 { 275 return Get(id); 276 } 277 278 public int Count() 279 { 280 return GetAll().Count(); 281 } 282 283 public int Count(Expression bool>> predicate) 284 { 285 return GetAll().Where(predicate).Count(); 286 } 287 288 public long LongCount() 289 { 290 return GetAll().LongCount(); 291 } 292 293 public long LongCount(Expression bool>> predicate) 294 { 295 return GetAll().Where(predicate).LongCount(); 296 } 297 298 } 299 }
2.3 GR.Data中创建DependencyRegister依赖注册类(从Startup中分解出来)
之后只要是在Data中添加的类需要依赖注入,都是在该类中添加
1 using System; 2 using GR.Core.Data; 3 using GR.Data.Repository; 4 using Microsoft.EntityFrameworkCore; 5 using Microsoft.Extensions.DependencyInjection; 6 7 namespace GR.Data 8 { 9 public class DependencyRegister 10 { 11 public static void ConfigureServices(IServiceCollection services) 12 { 13 services.AddDbContext(ServiceLifetime.Singleton); 14 services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>)); 15 } 16 } 17 }
2.3 GR.Servies中创建AccountService类,创建DTO实体模型,以及DependencyRegister依赖注册类
2.4 在gr.web中的startup添加依赖注册
3-结束
这样子登陆功能就完成了,其他的数据验证和.NET FRAMEWORK的一样