使用docker搭建Swagger
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用docker搭建Swagger相关的知识,希望对你有一定的参考价值。
参考技术A json文件挂在到容器中-p:宿主机端口:容器端口,将容器端口暴露给宿主机端口
-d:后台启动
-e:执行容器中/foo/swagger.json
-v:将宿主机中/home/service/swagger/swagger.json挂载到容器 /foo中执行
输入:http://主机IP:端口
NetCore 3.1 项目搭建反射依赖注入,Swagger结合Jwt,sqlSugar+EfCore异常中间件+Log4Net+MongoDb,Redis+Docker,丰富的公共类库,代码示例 下
十年河东,十年河西,莫欺少年穷
学无止境,精益求精
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 ; );
扩展方法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); );
扩展方法: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"; );
过滤器: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()); ;
通过反射依赖注入
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()); ));
异常处理中间件
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());
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";
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;//用来处理事务多表查询和复杂的操作
数据访问层代码示例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);
等等吧,中小企业项目用这个框架完全没问题
@天才卧龙的博客
以上是关于使用docker搭建Swagger的主要内容,如果未能解决你的问题,请参考以下文章