基于.net core 2.0+mysql+AceAdmin搭建一套快速开发框架

前言 .net core已经出来一段时间了,相信大家对.net core的概念已经很清楚了,这里就不再赘述。笔者目前也用.net core做过一些项目,并且将以前framework下的一些经验移植到了.net core下,并结合.net core本身的一些特性整理成此框架,以供学习参考。如有不足之处,欢迎指正。 先睹为快,演示地址:http://cloud.eggtwo.com/main/index 框架介绍 先来一张整体分层结构图 基础层 1.Cloud.Core项目是核心项目,主要实现缓存的操作、dapper操作、EF Repository、PageList、日志等操作 2.Cloud.Utility属于帮助类 领域层 3.Cloud.Entity实体对象,存放数据库映射实体、Fluent API配置、枚举字典、DbContext等 4.Cloud.UnitOfWork,操作数据库的网关,里面封装了对仓储的操作、dapper的操作、事务等 服务层 5.Cloud.Service 业务逻辑的实现 6.Cloud.Dto 数据传输对象,实体对象不直接和表现层接触,通过dto互转 表现层 7.Cloud.Framework,表现层框架,封装了超类controller,全局授权过滤器,全局异常过滤器,ActionFilter,HtmlHelper等操作 8.Cloud.Boss 启动项目 使用的技术 基于.net core 2.0的asp.net core mvc 基于.net core 2.0的ef dapper mysql 前端框架 aceAdmin 技术要点 1.实体基类定义 2.泛型仓储的封装 2.1仓储接口的定义,泛型约束T必须是BaseEntity类型 + View Code    2.2仓储接口的实现 + View Code    3.表部分字段更新实现 EF默认的更新方式是一个实体对应的表全部字段更新,那么我们想更新表的部分字段怎么处理? 首先定义需要更新的字段: public class PropertyExpression where T : BaseEntity { private PropertyExpression() { } private static List propertyList = new List(); public static PropertyExpression Init { get { propertyList.Clear(); return new PropertyExpression(); } } public PropertyExpression Property(Expression> expr) { var rtn = ""; if (expr.Body is UnaryExpression) { rtn = ((MemberExpression)((UnaryExpression)expr.Body).Operand).Member.Name; } else if (expr.Body is MemberExpression) { rtn = ((MemberExpression)expr.Body).Member.Name; } else if (expr.Body is ParameterExpression) { rtn = ((ParameterExpression)expr.Body).Type.Name; } propertyList.Add(rtn); return this; } public List ToList() { return propertyList; } }   EF更新的处理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public bool Update(T entity, bool isSaveChange = true, List updatePropertyList = null) { if (entity==null) { return false; } _dbContext.Set().Attach(entity); if (updatePropertyList==null) { _dbContext.Entry(entity).State = EntityState.Modified;//全字段更新 } else { updatePropertyList.ForEach(c => { _dbContext.Entry(entity).Property(c).IsModified = true; //部分字段更新的写法 }); } if (isSaveChange) { return SaveChanges() > 0; } return false; }   使用 1 2 3 4 5 6 7 8 var entity = _unitOfWork.SysRoleRep.Get(model.RoleId); if (entity == null) { throw new Exception("要查找的对象不存在"); } entity.Name = model.RoleName; var updatedPropertyList = PropertyExpression.Init.Property(c => c.Name).ToList(); _unitOfWork.SysRoleRep.Update(entity, true, updatedPropertyList);    4.动态加载实体到DbContext 1 2 3 4 5 6 7 8 9 10 11 public class EntityTypeConfiguration : IEntityTypeConfiguration where T : class { public void Configure(EntityTypeBuilder builder) { RelyConfigure(builder); } public virtual void RelyConfigure(EntityTypeBuilder builder) { } }    1 2 3 4 5 6 7 8 9 10 public class Sys_Error_LogConfiguration : EntityTypeConfiguration { public override void RelyConfigure(EntityTypeBuilder builder) { builder.ToTable("sys_error_log"); builder.HasKey(x => x.Id); base.RelyConfigure(builder); } }    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class EfDbContext : DbContext { public EfDbContext(DbContextOptions options) : base(options) { } //配置数据库连接 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { // optionsBuilder.UseSqlServer("xxxx connection string"); base.OnConfiguring(optionsBuilder); } //第一次使用EF功能时执行一次,以后不再执行 protected override void OnModelCreating(ModelBuilder modelBuilder) { //获取当前程序集中有基类并且基类是泛型的类 var typesToRegister = Assembly.GetExecutingAssembly().GetTypes().Where(c => c.BaseType != null && c.BaseType.IsGenericType).ToList(); foreach (var type in typesToRegister) { //泛型定义相同 if (type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>)) { dynamic configurationInstance = Activator.CreateInstance(type); modelBuilder.ApplyConfiguration(configurationInstance); } } base.OnModelCreating(modelBuilder); } }    5.工作单元 工作单元是对仓储和事务的封装 原理参考:https://docs.microsoft.com/zh-cn/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 public class EfUnitOfWork : IUnitOfWork { private EfDbContext _dbContext;//每次请求上下文只会创建一个 public EfUnitOfWork(EfDbContext context) { this._dbContext = context; } public int SaveChanges() { return _dbContext.SaveChanges(); } public async Task SaveChangesAsync() { return await _dbContext.SaveChangesAsync(); } private bool disposed = false; protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { _dbContext.Dispose();//随着工作单元的销毁而销毁 } } this.disposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public IDbContextTransaction BeginTransaction() { var scope = _dbContext.Database.BeginTransaction(); return scope; } public List SqlQuery(string sql, object param = null) where T : class { var con= _dbContext.Database.GetDbConnection(); if (con.State!= ConnectionState.Open) { con.Open(); } var list= MysqlDapperReader.SqlQuery(con, sql, param); return list; //throw new NotImplementedException(); } public Task> SqlQueryAsync(string sql, object param = null) where T : class { throw new NotImplementedException(); } #region Sys Repository private IRepository _sysUserRep; public IRepository SysUserRep { get { if (_sysUserRep == null) { //var s= HttpContext.Current.Items["currentUser"]; //var s = HttpContext.Current.RequestServices.GetService>(); //HttpContext.RequestServices.GetService>(); _sysUserRep = new Repository(_dbContext); } return _sysUserRep; } } private IRepository _sysRoleRep; public IRepository SysRoleRep { get { if (_sysRoleRep == null) { _sysRoleRep = new Repository(_dbContext); } return _sysRoleRep; } } private IRepository _sysRoleUserRep; public IRepository SysRoleUserRep { get { if (_sysRoleUserRep == null) { _sysRoleUserRep = new Repository(_dbContext); } return _sysRoleUserRep; } } private IRepository _sysPermissionRep; public IRepository SysPermissionRep { get { if (_sysPermissionRep == null) { _sysPermissionRep = new Repository(_dbContext); } return _sysPermissionRep; } } private IRepository _sysModuleRep; public IRepository SysModuleRep { get { if (_sysModuleRep == null) { _sysModuleRep = new Repository(_dbContext); } return _sysModuleRep; } } private IRepository _sysErrorLogRep; public IRepository SysErrorLogRep { get { if (_sysErrorLogRep == null) { _sysErrorLogRep = new Repository(_dbContext); } return _sysErrorLogRep; } } private IRepository _sysOperationLogRep; public IRepository SysOperationLogRep { get { if (_sysOperationLogRep == null) { _sysOperationLogRep = new Repository(_dbContext); } return _sysOperationLogRep; } } #endregion } 6.业务的实现方式  以前我是service中直接创建仓储然后用仓储操作数据库,方式如下: 这种方式比较繁琐,后来我将创建仓储统一放在工作单元中进行,在service中直接创建UnitOfWork,方式如下: 7.Service的动态注册 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public static class AutoIocRegister { /// /// 动态注入IOC,注意类和接口的命名规则,接口在类名前面加"I" /// /// /// 程序集名称 public static void BatchAddScoped(this IServiceCollection services, string assemblyName) { var libs = DependencyContext.Default.CompileLibraries; var serviceLib = libs.Where(c => c.Name.Contains(assemblyName)).FirstOrDefault(); var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(serviceLib.Name)); var serviceClassList = assembly.GetTypes().Where(c => c.IsClass).ToList(); foreach (var item in serviceClassList) { var interfaceName = "I" + item.Name; var interfaceType = assembly.GetTypes().Where(c => c.IsInterface && c.Name == interfaceName).FirstOrDefault(); if (interfaceType == null) continue; services.AddScoped(interfaceType, item); } } }  调用: 1 services.BatchAddScoped("Cloud.Service"); 8.日志记录: 日志分操作日志和错误日志,可以设置在数据库和文本中同时记录: 通过全局过滤器GlobalExceptionFilter和GlobalAuthorizeFilter处理   9.前端的封装(分页、弹出层、ajax等) 先放几张图吧,详细的以后再介绍 演示地址:http://cloud.eggtwo.com/main/index 作者:梦亦晓,转载请注明出处 本人拙作【问卷调查系统】,敬请赐教 如果此文能给您提供帮助,请点击右下角的【推荐】 如果您对此文有不同的见解或者意见,欢迎留言讨论https://www.cnblogs.com/eggTwo/p/9564101.html
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信