十年河东,十年河西,莫欺少年穷
学无止境,精益求精
1、通过反射自动注入接口及服务类,项目数据访问层和业务逻辑层分离
2、数据库操作使用EFCore
3、sqlSugar 实现数据库复杂查询
4、实例代码丰富
5、丰富的公共类库
6、支持swagger + jwt + 异常中间件 + mongoDb + redis + docker
下载地址:https://download.csdn.net/download/bbwolong/81748937
简单介绍如下:
示例代码:
扩展方法:JwtExtension
public static class JwtExtension { public static void AddJwt(this IServiceCollection services) { services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(x => { x.RequireHttpsMetadata = false; x.SaveToken = true; x.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(TokenManagementModel.Secret)), ValidIssuer = TokenManagementModel.Issuer, ValidAudience = TokenManagementModel.Audience, ValidateIssuer = false, ValidateAudience = false }; }); } }View Code
扩展方法Swagger
public static class SwaggerExtension { public static void AddSwagger(this IServiceCollection services, string apiName, string title = "", string version="V1") { services.AddSwaggerGen(c => { // 添加文档信息 c.SwaggerDoc(version, new OpenApiInfo { Version = version, Title = title }); AddSwagger(apiName, c); }); } public static void AddSwagger(this IServiceCollection services, string apiName, params OpenApiInfo[] infos) { services.AddSwaggerGen(c => { // 添加文档信息 foreach (var item in infos) { c.SwaggerDoc(item.Version, item); } AddSwagger(apiName, c); }); } private static void AddSwagger(string apiName, SwaggerGenOptions c) { c.DocumentFilter<HiddenApiFilter>(); c.DocumentFilter<SwaggerEnumFilter>(); c.SchemaFilter<HiddenFieldFilter>(); c.DocInclusionPredicate((docName, apiDesc) => apiDesc.GroupName == docName.ToUpper()); var basePath = Path.GetDirectoryName(AppContext.BaseDirectory); c.IncludeXmlComments(Path.Combine(basePath, $"{apiName}.xml"), true); c.IncludeXmlComments(Path.Combine(basePath, Constants.ModelDllXml), true); #region Jwt c.OperationFilter<AddResponseHeadersFilter>(); c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>(); c.OperationFilter<SecurityRequirementsOperationFilter>(); c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme { Description = "JWT授权(数据将在请求头中进行传递)直接在下面框中输入Bearer {token}(注意两者之间是一个空格) \"", Name = "Authorization",//jwt默认的参数名称 In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中) Type = SecuritySchemeType.ApiKey }); #endregion } public static void UseSwag(this IApplicationBuilder app, string version = "V1") { // 启用Swagger中间件 app.UseSwagger(c => c.RouteTemplate = "/swagger/{documentName}/swagger.json"); // 配置SwaggerUI app.UseSwaggerUI(c => { c.SwaggerEndpoint($"{Constants.VirtualPath}/swagger/{version}/swagger.json", version); }); } public static void UseSwag(this IApplicationBuilder app, params string[] versions) { // 启用Swagger中间件 app.UseSwagger(c => c.RouteTemplate = "/swagger/{documentName}/swagger.json"); // 配置SwaggerUI foreach (var version in versions) { app.UseSwaggerUI(c => { c.SwaggerEndpoint($"{Constants.VirtualPath}/swagger/{version}/swagger.json", version); }); } } }View Code
扩展方法:JsonExtension
public static class JsonExtension { public static void AddJson(this IServiceCollection services,bool resolver = true) { services.AddControllersWithViews().AddNewtonsoftJson(options => { if (resolver) { options.SerializerSettings.ContractResolver = new DefaultContractResolver(); } options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc; // 设置时区为 UTC) options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; }); } }View Code
过滤器:HiddenApiFilter
public class HiddenApiFilter : IDocumentFilter { public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) { foreach (var item in context.ApiDescriptions) { if (item.TryGetMethodInfo(out MethodInfo methodInfo)) { if (methodInfo.ReflectedType.CustomAttributes.Any(t => t.AttributeType == typeof(HiddenAttribute)) || methodInfo.CustomAttributes.Any(t => t.AttributeType == typeof(HiddenAttribute))) { var key = "/" + item.RelativePath.TrimEnd('/'); if (key.Contains("?")) { int idx = key.IndexOf("?", StringComparison.Ordinal); key = key.Substring(0, idx); } if (swaggerDoc.Paths.ContainsKey(key)) { swaggerDoc.Paths.Remove(key); } } } } } } public class HiddenFieldFilter : ISchemaFilter { public void Apply(OpenApiSchema schema, SchemaFilterContext context) { if (schema?.Properties == null) { return; } var name = context.Type.FullName; var excludedProperties = context.Type.GetProperties(); foreach (var property in excludedProperties) { var attribute = property.GetCustomAttribute<HiddenFieldAttribute>(); if (attribute != null && schema.Properties.ContainsKey(property.Name.ToLowerStart())) { schema.Properties.Remove(property.Name.ToLowerStart()); } }; } }View Code
通过反射依赖注入
public static class DIRegister { public static void RegisterDI(this IServiceCollection services) { var rootPath = Path.GetDirectoryName(typeof(DIExtension).Assembly.Location); var rootDir = new DirectoryInfo(rootPath); var basePath = rootDir.FullName; //注册业务访问层 接口 与 实现类 注册为 AddScoped RegisterDll(services, basePath, Constants.ServiceDllFullName, Constants.ServiceSuffix ); //注册数据访问层 接口 与 实现类 注册为 AddScoped RegisterDll(services, basePath, Constants.RepositoryDllFullName, Constants.RepositorySuffix ); } private static void RegisterDll(IServiceCollection services, string basePath, string dllName, params string[] endsWith) { ///D:\525gitProject\netcore\WuAnManager\WuAnChangeApi\bin\Debug\netcoreapp3.1\WuAnService.dll string assemblyPath = Path.Combine(basePath, dllName); var assembly = Assembly.LoadFrom(assemblyPath); services.RegisterAssemblyEndsWith(assembly, endsWith); } public static void DIListPage(this IApplicationBuilder app, IServiceCollection _services) { app.Map($"/api/allservices", builder => builder.Run(async context => { var sb = new StringBuilder(); sb.Append("<h1>All Services</h1>"); sb.Append("<table><thead>"); sb.Append("<tr><th>Type</th><th>Lifetime</th><th>Instance</th></tr>"); sb.Append("</thead><tbody>"); foreach (var svc in _services) { sb.Append("<tr>"); sb.Append($"<td>{svc.ServiceType.FullName}</td>"); sb.Append($"<td>{svc.Lifetime}</td>"); sb.Append($"<td>{svc.ImplementationType?.FullName}</td>"); sb.Append("</tr>"); } sb.Append("</tbody></table>"); await context.Response.WriteAsync(sb.ToString()); })); } }View Code
异常处理中间件
public class ExceptionMiddlewares { private ILog log; private readonly RequestDelegate next; private IHostingEnvironment environment; public ExceptionMiddlewares(RequestDelegate next, IHostingEnvironment environment) { this.log = LogManager.GetLogger(Startup.repository.Name, typeof(ExceptionMiddlewares)); this.next = next; this.environment = environment; } public async Task Invoke(HttpContext context) { try { await next.Invoke(context); var features = context.Features; } catch(AssertException ex) { if (context.Response.HasStarted) { throw; } await Response(context, ex.HttpStatusCode, ex.Message); } catch (Exception e) { Log.Inst.Error($"wuanapi系统异常:{e.ToString()}"); await HandleException(context, e); } } private async Task HandleException(HttpContext context, Exception e) { context.Response.StatusCode = 500; context.Response.ContentType = "text/json;charset=utf-8;"; string error = ""; var json = new { message = e.Message }; log.Error(json); error = JsonConvert.SerializeObject(json); await context.Response.WriteAsync(error); } private async Task Response(HttpContext httpContext, int statusCode, string message) { httpContext.Response.StatusCode = statusCode; httpContext.Response.ContentType = "application/json; charset=utf-8"; var result = CommonBaseResponse.SetResponse(false, message); await httpContext.Response.WriteAsync(result.ToJson()); } }View Code
SqlSugar 帮助类
public class DataRepository { public static string NewGuid() { return Guid.NewGuid().ToString("N"); } /// <summary> /// 获取返回的列表 /// </summary> /// <typeparam name="U"></typeparam> /// <param name="sql"></param> /// <param name="orderby"></param> /// <returns></returns> public static List<U> GetListBySql<U>(string sql, string orderby = "") where U : class, new() { SugarContext sugar = new SugarContext(); List<U> result = null; using (var db = sugar.Db) { if (string.IsNullOrEmpty(orderby)) { result = db.SqlQueryable<U>(sql).ToList(); } else { result = db.SqlQueryable<U>(sql).OrderBy(orderby).ToList(); } } return result; } /// <summary> /// 获取返回的列表-参数化 /// </summary> /// <typeparam name="U"></typeparam> /// <param name="sql"></param> /// <param name="where"></param> /// <param name="parameters"></param> /// <returns></returns> public static List<U> GetListBySql<U>(string sql, string where, object parameters) where U : class, new() { SugarContext sugar = new SugarContext(); List<U> result = null; using (var db = sugar.Db) { result = db.SqlQueryable<U>(sql).Where(where, parameters).ToList(); } return result; } /// <summary> /// 获取DbSet 第一行 /// </summary> /// <typeparam name="U"></typeparam> /// <param name="sql"></param> /// <returns></returns> public static U GetOneBySql<U>(string sql) where U : class, new() { SugarContext sugar = new SugarContext(); U result = null; using (var db = sugar.Db) { result = db.SqlQueryable<U>(sql).First(); } return result; } /// <summary> /// 获取第一行第一列的值 并转化为Int /// </summary> /// <param name="sql"></param> /// <returns></returns> public static int GetInt(string sql) { SugarContext sugar = new SugarContext(); using (var db = sugar.Db) { return db.Ado.GetInt(sql); } } /// <summary> /// 获取第一行第一列的值 并转化为Double /// </summary> /// <param name="sql"></param> /// <returns></returns> public static double GetDouble(string sql) { SugarContext sugar = new SugarContext(); using (var db = sugar.Db) { return db.Ado.GetDouble(sql); } } /// <summary> /// 执行Sql 查询单个实体 /// </summary> /// <typeparam name="E"></typeparam> /// <typeparam name="U"></typeparam> /// <param name="sql"></param> /// <param name="OrderBy"></param> /// <param name="u"></param> /// <returns></returns> public static E PageOne<E>(string sql) where E : class, new() { SugarContext sugar = new SugarContext(); var db = sugar.Db; var one = db.SqlQueryable<E>(sql).ToList().FirstOrDefault(); return one; } /// <summary> /// 查询结果List的第一条记录 /// </summary> /// <typeparam name="E"></typeparam> /// <param name="sql"></param> /// <param name="where"></param> /// <param name="parameters"></param> /// <returns></returns> public static E PageOne<E>(string sql, string where, object parameters) where E : class, new() { SugarContext sugar = new SugarContext(); if (parameters == null) { return PageOne<E>(sql); } var db = sugar.Db; var one = db.SqlQueryable<E>(sql).Where(where, parameters).ToList().FirstOrDefault(); return one; } public static PaginationListModel<E> PageQuery<E, U>(string sql, string OrderBy, U u) where U : PaginationModel where E : class, new() { SugarContext sugar = new SugarContext(); var db = sugar.Db; int total = 0; List<E> list = null; if (OrderBy.IsNullOrWhiteSpace()) { list = db.SqlQueryable<E>(sql).ToPageList(u.pageNumber, u.pageSize, ref total); } else { list = db.SqlQueryable<E>(sql).OrderBy(OrderBy).ToPageList(u.pageNumber, u.pageSize, ref total); } return new PaginationListModel<E>() { data = list, pagination = new BasePaginationModel() { pageNumber = u.pageNumber, pageSize = u.pageSize, total = total } }; } /// <summary> /// 第一行第一列 /// </summary> /// <param name="sql"></param> /// <param name="parameters"></param> /// <returns></returns> public static object ExecuteScalar(string sql, object parameters = null) { SugarContext sugar = new SugarContext(); using (var db = sugar.Db) { return db.Ado.GetScalar(sql, parameters); } } /// <summary> /// 执行Update insert 等操作 /// </summary> /// <param name="sql"></param> /// <param name="parameters"></param> /// <returns></returns> public static int ExecuteCommand(string sql, object parameters = null) { SugarContext sugar = new SugarContext(); using (var db = sugar.Db) { return db.Ado.ExecuteCommand(sql, parameters); } } /// <summary> /// 第一行第一列 /// </summary> public static object ExecuteScalar(string sql) { SugarContext sugar = new SugarContext(); using (var db = sugar.Db) { return db.Ado.GetScalar(sql); } } /// <summary> /// 第一行第一列 - 异步 /// </summary> public static async Task<object> ExecuteScalarAsync(string sql, object parameters = null) { SugarContext sugar = new SugarContext(); using (var db = sugar.Db) { return await db.Ado.GetScalarAsync(sql, parameters); } } /// <summary> /// 第一行第一列 - 异步 /// </summary> public static async Task<object> ExecuteScalarAsync(string sql) { SugarContext sugar = new SugarContext(); using (var db = sugar.Db) { return await db.Ado.GetScalarAsync(sql); } } public static E GetOneBySql<E>(string sql, object parameters = null) where E : class { SugarContext sugar = new SugarContext(); using (var db = sugar.Db) { return db.Ado.SqlQuerySingle<E>(sql, parameters); } } /// <summary> /// 第一行第一列 - 异步 /// </summary> public static async Task<E> GetOneBySqlAsync<E>(string sql, object parameters = null) where E : class { SugarContext sugar = new SugarContext(); using (var db = sugar.Db) { return await db.Ado.SqlQuerySingleAsync<E>(sql, parameters); } } public static List<E> GetBySql<E>(string sql, object parameters = null) where E : class { SugarContext sugar = new SugarContext(); using (var db = sugar.Db) { return db.Ado.SqlQuery<E>(sql, parameters); } } public static async Task<List<E>> GetBySqlAsync<E>(string sql, object parameters = null) where E : class { SugarContext sugar = new SugarContext(); using (var db = sugar.Db) { return await db.Ado.SqlQueryAsync<E>(sql, parameters); } } /// <summary> /// 执行事务 /// </summary> /// <param name="sqls"></param> public static void ExecTransaction(List<string> sqls) { SugarContext sugar = new SugarContext(); using (var db = sugar.Db) { try { db.Ado.BeginTran(); foreach (var item in sqls) { db.Ado.ExecuteCommand(item); } db.Ado.CommitTran(); } catch (Exception ex) { db.Ado.RollbackTran(); throw ex; } } } } public class DataRepository<T> where T : class, new() { public static PaginationListModel<T> PageQuery<U>(string sql, U u, string where = "") where U : OrderByPaginationModel { SugarContext sugar = new SugarContext(); var db = sugar.Db; var query = db.SqlQueryable<T>(sql); if (where.NotNullOrWhiteSpace()) { query = query.Where(where, u.ToSqlParam()); } if (u.OrderBy.NotNullOrWhiteSpace()) { query = query.OrderBy(u.OrderBy); } int total = 0; var list = query.ToPageList(u.pageNumber, u.pageSize, ref total); return new PaginationListModel<T>() { data = list, pagination = new BasePaginationModel() { pageNumber = u.pageNumber, pageSize = u.pageSize, total = total } }; } } internal static class SqlExtend { public static string Equal(this string source, string field) { return $"{source} = {field}"; } public static string Like(this string source) { return $"%{source}%"; } public static Dictionary<string, object> ToSqlParam<T>(this T t) where T : class { var fields = typeof(T).GetProperties(); var fieldDict = new Dictionary<string, object>(); foreach (var item in fields) { fieldDict.Add(item.Name, item.GetValue(t)); } return fieldDict; } public static List<Dictionary<string, object>> ToSqlParam<T>(this List<T> tList) where T : class { var result = new List<Dictionary<string, object>>(); foreach (var item in tList) { result.Add(ToSqlParam(item)); } return result; } public static string Top(this string source, int topCount) { return source.Replace("select", $"select top {topCount}"); } public static string Where(this string source, params string[] conditions) { var where = new StringBuilder(" where 1 = 1 "); foreach (var item in conditions) { where.Append($" and {item} "); } return $"{source} {where}"; } }View Code
sqlSugarDbContxt上下文
public class SugarContext { /// 获取连接字符串 private static string Connection = ConfigCommon.Get("WuAnFundDbContext"); public SugarContext(string connection = "") { Db = new SqlSugarClient(new ConnectionConfig() { ConnectionString = connection.IsNullOrWhiteSpace() ? Connection : connection, DbType = DbType.SqlServer, InitKeyType = InitKeyType.Attribute,//从特性读取主键和自增列信息 IsAutoCloseConnection = true,//开启自动释放模式和EF原理一样我就不多解释了 }); //调式代码 用来打印SQL Db.Aop.OnLogExecuting = (sql, pars) => { Console.WriteLine(sql + "\r\n" + Db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value))); Console.WriteLine(); }; } //注意:不能写成静态的 public SqlSugarClient Db;//用来处理事务多表查询和复杂的操作 }View Code
数据访问层代码示例1
/// <summary> /// 数据库访问层 /// </summary> public class StudentRepository: IStudentRepository { public List<StudentModel> GetStudents() { string sql = "select * from Student where StudentAge<100 order by StudentAge"; return DataRepository.GetBySql<StudentModel>(sql); } public List<StudentModel> GetStudentsByName(SearchStudentByNameModel searchParam) { string sql = "select * from Student where 1=1 "; if (!string.IsNullOrEmpty(searchParam.StudentName)) { sql += " and StudentName=@StudentName"; } var parm = new { StudentName = searchParam.StudentName }; return DataRepository.GetBySql<StudentModel>(sql, parm); } public PaginationListModel<StudentModel> GetPaginationStudents(SearchStudentModel searchParam) { string sql = string.Format(@"SELECT * FROM [dbo].[Student] "); string where = " 1=1 and StudentName<>@StudentName"; searchParam.OrderBy = "createTime desc"; return DataRepository<StudentModel>.PageQuery <SearchStudentModel>(sql, searchParam, where); } public PaginationListModel<StudentModel> GetPageStudents(SearchStudentModel_2 searchParam) { string sql = string.Format(@"SELECT * FROM [dbo].[Student] where 1=1 "); sql+= " and StudentName<>'"+ searchParam .StudentName+ "'"; return DataRepository.PageQuery<StudentModel, SearchStudentModel_2>(sql, "CreateTime desc", searchParam); } }View Code
等等吧,中小企业项目用这个框架完全没问题
@天才卧龙的博客