HostApp.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. using AspNetCoreRateLimit;
  2. using Autofac;
  3. using IdentityServer4.AccessTokenValidation;
  4. using Microsoft.AspNetCore.Authentication;
  5. using Microsoft.AspNetCore.Authentication.JwtBearer;
  6. using Microsoft.AspNetCore.Builder;
  7. using Microsoft.AspNetCore.Hosting;
  8. using Microsoft.AspNetCore.Http;
  9. using Microsoft.Extensions.Configuration;
  10. using Microsoft.Extensions.DependencyInjection;
  11. using Microsoft.Extensions.DependencyInjection.Extensions;
  12. using Microsoft.Extensions.Hosting;
  13. using Microsoft.Extensions.DependencyModel;
  14. using Microsoft.IdentityModel.Tokens;
  15. using Microsoft.OpenApi.Models;
  16. using Newtonsoft.Json;
  17. using Newtonsoft.Json.Serialization;
  18. using System;
  19. using System.Collections.Generic;
  20. using System.IdentityModel.Tokens.Jwt;
  21. using System.Linq;
  22. using System.Reflection;
  23. using System.Text;
  24. using Mapster;
  25. using Yitter.IdGenerator;
  26. using FluentValidation;
  27. using FluentValidation.AspNetCore;
  28. using ZhonTai.Admin.Core.Auth;
  29. using ZhonTai.Admin.Tools.Cache;
  30. using ZhonTai.Common.Helpers;
  31. using ZhonTai.Admin.Core.Db;
  32. using ZhonTai.Admin.Core.Extensions;
  33. using ZhonTai.Admin.Core.Filters;
  34. using ZhonTai.Admin.Core.Logs;
  35. using ZhonTai.Admin.Core.RegisterModules;
  36. using System.IO;
  37. using Microsoft.OpenApi.Any;
  38. using Microsoft.AspNetCore.Mvc.Controllers;
  39. using ZhonTai.Admin.Core.Attributes;
  40. using ZhonTai.Admin.Core.Configs;
  41. using ZhonTai.Admin.Core.Consts;
  42. using MapsterMapper;
  43. using ZhonTai.DynamicApi;
  44. using NLog.Web;
  45. using Autofac.Extensions.DependencyInjection;
  46. using Microsoft.AspNetCore.Mvc;
  47. using ZhonTai.Admin.Core.Startup;
  48. using ZhonTai.Admin.Core.Conventions;
  49. using FreeSql;
  50. using ZhonTai.Admin.Services.User;
  51. using ZhonTai.Admin.Core.Middlewares;
  52. using ZhonTai.Admin.Core.Dto;
  53. using ZhonTai.DynamicApi.Attributes;
  54. namespace ZhonTai.Admin.Core;
  55. /// <summary>
  56. /// 宿主应用
  57. /// </summary>
  58. public class HostApp
  59. {
  60. readonly HostAppOptions _hostAppOptions;
  61. public HostApp()
  62. {
  63. }
  64. public HostApp(HostAppOptions hostAppOptions)
  65. {
  66. _hostAppOptions = hostAppOptions;
  67. }
  68. /// <summary>
  69. /// 运行应用
  70. /// </summary>
  71. /// <param name="args"></param>
  72. public void Run(string[] args)
  73. {
  74. var builder = WebApplication.CreateBuilder(args);
  75. //使用NLog日志
  76. builder.Host.UseNLog();
  77. var services = builder.Services;
  78. var env = builder.Environment;
  79. var configuration = builder.Configuration;
  80. var configHelper = new ConfigHelper();
  81. var appConfig = ConfigHelper.Get<AppConfig>("appconfig", env.EnvironmentName) ?? new AppConfig();
  82. //添加配置
  83. builder.Configuration.AddJsonFile("./Configs/ratelimitconfig.json", optional: true, reloadOnChange: true);
  84. if (env.EnvironmentName.NotNull())
  85. {
  86. builder.Configuration.AddJsonFile($"./Configs/ratelimitconfig.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
  87. }
  88. builder.Configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
  89. if (env.EnvironmentName.NotNull())
  90. {
  91. builder.Configuration.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
  92. }
  93. //应用配置
  94. services.AddSingleton(appConfig);
  95. //使用Autofac容器
  96. builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
  97. //配置Autofac容器
  98. builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
  99. {
  100. // 控制器注入
  101. builder.RegisterModule(new ControllerModule());
  102. // 单例注入
  103. builder.RegisterModule(new SingleInstanceModule(appConfig));
  104. // 仓储注入
  105. builder.RegisterModule(new RepositoryModule(appConfig));
  106. // 服务注入
  107. builder.RegisterModule(new ServiceModule(appConfig));
  108. });
  109. //配置Kestrel服务器
  110. builder.WebHost.ConfigureKestrel((context, options) =>
  111. {
  112. //设置应用服务器Kestrel请求体最大为100MB
  113. options.Limits.MaxRequestBodySize = 1024 * 1024 * 100;
  114. });
  115. //访问地址
  116. builder.WebHost.UseUrls(appConfig.Urls);
  117. //配置服务
  118. ConfigureServices(services, env, configuration, configHelper, appConfig);
  119. var app = builder.Build();
  120. //配置中间件
  121. ConfigureMiddleware(app, env, configuration, appConfig);
  122. app.Run();
  123. }
  124. /// <summary>
  125. /// 实体类型重命名
  126. /// </summary>
  127. /// <param name="modelType"></param>
  128. /// <returns></returns>
  129. private string DefaultSchemaIdSelector(Type modelType)
  130. {
  131. if (!modelType.IsConstructedGenericType) return modelType.Name.Replace("[]", "Array");
  132. var prefix = modelType.GetGenericArguments()
  133. .Select(DefaultSchemaIdSelector)
  134. .Aggregate((previous, current) => previous + current);
  135. return modelType.Name.Split('`').First() + prefix;
  136. }
  137. /// <summary>
  138. /// 配置服务
  139. /// </summary>
  140. /// <param name="services"></param>
  141. /// <param name="env"></param>
  142. /// <param name="configuration"></param>
  143. /// <param name="configHelper"></param>
  144. /// <param name="appConfig"></param>
  145. private void ConfigureServices(IServiceCollection services, IWebHostEnvironment env, IConfiguration configuration, ConfigHelper configHelper, AppConfig appConfig)
  146. {
  147. var hostAppContext = new HostAppContext()
  148. {
  149. Services = services,
  150. Environment = env,
  151. Configuration = configuration
  152. };
  153. _hostAppOptions?.ConfigurePreServices?.Invoke(hostAppContext);
  154. //雪花漂移算法
  155. var idGeneratorOptions = new IdGeneratorOptions(1) { WorkerIdBitLength = 6 };
  156. _hostAppOptions?.ConfigureIdGenerator?.Invoke(idGeneratorOptions);
  157. YitIdHelper.SetIdGenerator(idGeneratorOptions);
  158. //权限处理
  159. services.AddScoped<IPermissionHandler, PermissionHandler>();
  160. // ClaimType不被更改
  161. JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
  162. //用户信息
  163. services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
  164. services.TryAddScoped<IUser, User>();
  165. //数据库配置
  166. var dbConfig = ConfigHelper.Get<DbConfig>("dbconfig", env.EnvironmentName);
  167. services.AddSingleton(dbConfig);
  168. //添加数据库
  169. if (!_hostAppOptions.CustomInitDb)
  170. {
  171. services.AddDb(env, _hostAppOptions);
  172. }
  173. //上传配置
  174. var uploadConfig = ConfigHelper.Load("uploadconfig", env.EnvironmentName, true);
  175. services.Configure<UploadConfig>(uploadConfig);
  176. //程序集
  177. Assembly[] assemblies = null;
  178. if(appConfig.AssemblyNames?.Length > 0)
  179. {
  180. assemblies = DependencyContext.Default.RuntimeLibraries
  181. .Where(a => appConfig.AssemblyNames.Contains(a.Name))
  182. .Select(o => Assembly.Load(new AssemblyName(o.Name))).ToArray();
  183. }
  184. #region Mapster 映射配置
  185. services.AddScoped<IMapper>(sp => new Mapper());
  186. if(assemblies?.Length > 0)
  187. {
  188. TypeAdapterConfig.GlobalSettings.Scan(assemblies);
  189. }
  190. #endregion Mapster 映射配置
  191. #region Cors 跨域
  192. services.AddCors(options =>
  193. {
  194. options.AddPolicy(AdminConsts.RequestPolicyName, policy =>
  195. {
  196. var hasOrigins = appConfig.CorUrls?.Length > 0;
  197. if (hasOrigins)
  198. {
  199. policy.WithOrigins(appConfig.CorUrls);
  200. }
  201. else
  202. {
  203. policy.AllowAnyOrigin();
  204. }
  205. policy
  206. .AllowAnyHeader()
  207. .AllowAnyMethod();
  208. if (hasOrigins)
  209. {
  210. policy.AllowCredentials();
  211. }
  212. });
  213. //允许任何源访问Api策略,使用时在控制器或者接口上增加特性[EnableCors(AdminConsts.AllowAnyPolicyName)]
  214. options.AddPolicy(AdminConsts.AllowAnyPolicyName, policy =>
  215. {
  216. policy
  217. .AllowAnyOrigin()
  218. .AllowAnyHeader()
  219. .AllowAnyMethod();
  220. });
  221. });
  222. #endregion Cors 跨域
  223. #region 身份认证授权
  224. var jwtConfig = ConfigHelper.Get<JwtConfig>("jwtconfig", env.EnvironmentName);
  225. services.TryAddSingleton(jwtConfig);
  226. if (appConfig.IdentityServer.Enable)
  227. {
  228. //is4
  229. services.AddAuthentication(options =>
  230. {
  231. options.DefaultScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
  232. options.DefaultChallengeScheme = nameof(ResponseAuthenticationHandler); //401
  233. options.DefaultForbidScheme = nameof(ResponseAuthenticationHandler); //403
  234. })
  235. .AddJwtBearer(options =>
  236. {
  237. options.Authority = appConfig.IdentityServer.Url;
  238. options.RequireHttpsMetadata = false;
  239. options.Audience = "admin.server.api";
  240. })
  241. .AddScheme<AuthenticationSchemeOptions, ResponseAuthenticationHandler>(nameof(ResponseAuthenticationHandler), o => { });
  242. }
  243. else
  244. {
  245. //jwt
  246. services.AddAuthentication(options =>
  247. {
  248. options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
  249. options.DefaultChallengeScheme = nameof(ResponseAuthenticationHandler); //401
  250. options.DefaultForbidScheme = nameof(ResponseAuthenticationHandler); //403
  251. })
  252. .AddJwtBearer(options =>
  253. {
  254. options.TokenValidationParameters = new TokenValidationParameters
  255. {
  256. ValidateIssuer = true,
  257. ValidateAudience = true,
  258. ValidateLifetime = true,
  259. ValidateIssuerSigningKey = true,
  260. ValidIssuer = jwtConfig.Issuer,
  261. ValidAudience = jwtConfig.Audience,
  262. IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfig.SecurityKey)),
  263. ClockSkew = TimeSpan.Zero
  264. };
  265. })
  266. .AddScheme<AuthenticationSchemeOptions, ResponseAuthenticationHandler>(nameof(ResponseAuthenticationHandler), o => { });
  267. }
  268. #endregion 身份认证授权
  269. #region Swagger Api文档
  270. if (env.IsDevelopment() || appConfig.Swagger.Enable)
  271. {
  272. services.AddSwaggerGen(options =>
  273. {
  274. appConfig.Swagger.Projects?.ForEach(project =>
  275. {
  276. options.SwaggerDoc(project.Code.ToLower(), new OpenApiInfo
  277. {
  278. Title = project.Name,
  279. Version = project.Version,
  280. Description = project.Description
  281. });
  282. //c.OrderActionsBy(o => o.RelativePath);
  283. });
  284. options.CustomOperationIds(apiDesc =>
  285. {
  286. var controllerAction = apiDesc.ActionDescriptor as ControllerActionDescriptor;
  287. return controllerAction.ControllerName + "-" + controllerAction.ActionName;
  288. });
  289. options.ResolveConflictingActions(apiDescription => apiDescription.First());
  290. options.CustomSchemaIds(modelType => DefaultSchemaIdSelector(modelType));
  291. //支持多分组
  292. options.DocInclusionPredicate((docName, apiDescription) =>
  293. {
  294. var nonGroup = false;
  295. var groupNames = new List<string>();
  296. var dynamicApiAttribute = apiDescription.ActionDescriptor.EndpointMetadata.FirstOrDefault(x => x is DynamicApiAttribute);
  297. if (dynamicApiAttribute != null)
  298. {
  299. var dynamicApi = dynamicApiAttribute as DynamicApiAttribute;
  300. if(dynamicApi.GroupNames?.Length > 0)
  301. {
  302. groupNames.AddRange(dynamicApi.GroupNames);
  303. }
  304. }
  305. var apiGroupAttribute = apiDescription.ActionDescriptor.EndpointMetadata.FirstOrDefault(x => x is ApiGroupAttribute);
  306. if (apiGroupAttribute != null)
  307. {
  308. var apiGroup = apiGroupAttribute as ApiGroupAttribute;
  309. if (apiGroup.GroupNames?.Length > 0)
  310. {
  311. groupNames.AddRange(apiGroup.GroupNames);
  312. }
  313. nonGroup = apiGroup.NonGroup;
  314. }
  315. return docName == apiDescription.GroupName || groupNames.Any(a => a == docName) || nonGroup;
  316. });
  317. string[] xmlFiles = Directory.GetFiles(AppContext.BaseDirectory, "*.xml");
  318. if (xmlFiles.Length > 0)
  319. {
  320. foreach (var xmlFile in xmlFiles)
  321. {
  322. options.IncludeXmlComments(xmlFile, true);
  323. }
  324. }
  325. var server = new OpenApiServer()
  326. {
  327. Url = appConfig.Swagger.Url,
  328. Description = ""
  329. };
  330. if (appConfig.ApiUI.Footer.Enable)
  331. {
  332. server.Extensions.Add("extensions", new OpenApiObject
  333. {
  334. ["copyright"] = new OpenApiString(appConfig.ApiUI.Footer.Content)
  335. });
  336. }
  337. options.AddServer(server);
  338. options.SchemaFilter<EnumSchemaFilter>();
  339. #region 添加设置Token的按钮
  340. if (appConfig.IdentityServer.Enable)
  341. {
  342. //添加Jwt验证设置
  343. options.AddSecurityRequirement(new OpenApiSecurityRequirement()
  344. {
  345. {
  346. new OpenApiSecurityScheme
  347. {
  348. Reference = new OpenApiReference
  349. {
  350. Id = "oauth2",
  351. Type = ReferenceType.SecurityScheme
  352. }
  353. },
  354. new List<string>()
  355. }
  356. });
  357. //统一认证
  358. options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
  359. {
  360. Type = SecuritySchemeType.OAuth2,
  361. Description = "oauth2登录授权",
  362. Flows = new OpenApiOAuthFlows
  363. {
  364. Implicit = new OpenApiOAuthFlow
  365. {
  366. AuthorizationUrl = new Uri($"{appConfig.IdentityServer.Url}/connect/authorize"),
  367. Scopes = new Dictionary<string, string>
  368. {
  369. { "admin.server.api", "admin后端api" }
  370. }
  371. }
  372. }
  373. });
  374. }
  375. else
  376. {
  377. //添加Jwt验证设置
  378. options.AddSecurityRequirement(new OpenApiSecurityRequirement()
  379. {
  380. {
  381. new OpenApiSecurityScheme
  382. {
  383. Reference = new OpenApiReference
  384. {
  385. Id = "Bearer",
  386. Type = ReferenceType.SecurityScheme
  387. }
  388. },
  389. new List<string>()
  390. }
  391. });
  392. options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
  393. {
  394. Description = "Value: Bearer {token}",
  395. Name = "Authorization",
  396. In = ParameterLocation.Header,
  397. Type = SecuritySchemeType.ApiKey
  398. });
  399. }
  400. #endregion 添加设置Token的按钮
  401. });
  402. }
  403. #endregion Swagger Api文档
  404. #region 操作日志
  405. if (appConfig.Log.Operation)
  406. {
  407. services.AddScoped<ILogHandler, LogHandler>();
  408. }
  409. #endregion 操作日志
  410. #region 控制器
  411. void mvcConfigure(MvcOptions options)
  412. {
  413. //options.Filters.Add<ControllerExceptionFilter>();
  414. options.Filters.Add<ValidateInputFilter>();
  415. if (appConfig.Validate.Login || appConfig.Validate.Permission)
  416. {
  417. options.Filters.Add<ValidatePermissionAttribute>();
  418. }
  419. //在具有较高的 Order 值的筛选器之前运行 before 代码
  420. //在具有较高的 Order 值的筛选器之后运行 after 代码
  421. if (appConfig.DynamicApi.FormatResult)
  422. {
  423. options.Filters.Add<FormatResultFilter>(20);
  424. }
  425. if (appConfig.Log.Operation)
  426. {
  427. options.Filters.Add<ControllerLogFilter>(10);
  428. }
  429. //禁止去除ActionAsync后缀
  430. //options.SuppressAsyncSuffixInActionNames = false;
  431. if (env.IsDevelopment() || appConfig.Swagger.Enable)
  432. {
  433. //API分组约定
  434. options.Conventions.Add(new ApiGroupConvention());
  435. }
  436. }
  437. var mvcBuilder = appConfig.AppType switch
  438. {
  439. AppType.Controllers => services.AddControllers(mvcConfigure),
  440. AppType.ControllersWithViews => services.AddControllersWithViews(mvcConfigure),
  441. AppType.MVC => services.AddMvc(mvcConfigure),
  442. _ => services.AddControllers(mvcConfigure)
  443. };
  444. if (assemblies?.Length > 0)
  445. {
  446. foreach (var assembly in assemblies)
  447. {
  448. services.AddValidatorsFromAssembly(assembly);
  449. }
  450. }
  451. services.AddFluentValidationAutoValidation();
  452. mvcBuilder.AddNewtonsoftJson(options =>
  453. {
  454. //忽略循环引用
  455. options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
  456. //使用驼峰 首字母小写
  457. options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
  458. //设置时间格式
  459. options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
  460. })
  461. .AddControllersAsServices();
  462. #endregion 控制器
  463. services.AddHttpClient();
  464. _hostAppOptions?.ConfigureServices?.Invoke(hostAppContext);
  465. #region 缓存
  466. var cacheConfig = ConfigHelper.Get<CacheConfig>("cacheconfig", env.EnvironmentName);
  467. if (cacheConfig.Type == CacheType.Redis)
  468. {
  469. var csredis = new CSRedis.CSRedisClient(cacheConfig.Redis.ConnectionString);
  470. RedisHelper.Initialization(csredis);
  471. services.AddSingleton<ICacheTool, RedisCacheTool>();
  472. }
  473. else
  474. {
  475. services.AddMemoryCache();
  476. services.AddSingleton<ICacheTool, MemoryCacheTool>();
  477. }
  478. #endregion 缓存
  479. #region IP限流
  480. if (appConfig.RateLimit)
  481. {
  482. services.AddIpRateLimit(configuration, cacheConfig);
  483. }
  484. #endregion IP限流
  485. //阻止NLog接收状态消息
  486. services.Configure<ConsoleLifetimeOptions>(opts => opts.SuppressStatusMessages = true);
  487. //性能分析
  488. if (appConfig.MiniProfiler)
  489. {
  490. services.AddMiniProfiler();
  491. }
  492. //动态api
  493. services.AddDynamicApi(options =>
  494. {
  495. Assembly[] assemblies = DependencyContext.Default.RuntimeLibraries
  496. .Where(a => a.Name.EndsWith("Service"))
  497. .Select(o => Assembly.Load(new AssemblyName(o.Name))).ToArray();
  498. options.AddAssemblyOptions(assemblies);
  499. options.FormatResult = appConfig.DynamicApi.FormatResult;
  500. options.FormatResultType = typeof(ResultOutput<>);
  501. _hostAppOptions?.ConfigureDynamicApi?.Invoke(options);
  502. });
  503. _hostAppOptions?.ConfigurePostServices?.Invoke(hostAppContext);
  504. }
  505. /// <summary>
  506. /// 配置中间件
  507. /// </summary>
  508. /// <param name="app"></param>
  509. /// <param name="env"></param>
  510. /// <param name="configuration"></param>
  511. /// <param name="appConfig"></param>
  512. private void ConfigureMiddleware(WebApplication app, IWebHostEnvironment env, IConfiguration configuration, AppConfig appConfig)
  513. {
  514. var hostAppMiddlewareContext = new HostAppMiddlewareContext()
  515. {
  516. App = app,
  517. Environment = env,
  518. Configuration = configuration
  519. };
  520. _hostAppOptions?.ConfigurePreMiddleware?.Invoke(hostAppMiddlewareContext);
  521. //异常处理
  522. app.UseMiddleware<ExceptionMiddleware>();
  523. //IP限流
  524. if (appConfig.RateLimit)
  525. {
  526. app.UseIpRateLimiting();
  527. }
  528. //性能分析
  529. if (appConfig.MiniProfiler)
  530. {
  531. app.UseMiniProfiler();
  532. }
  533. //静态文件
  534. app.UseDefaultFiles();
  535. app.UseStaticFiles();
  536. app.UseUploadConfig();
  537. //路由
  538. app.UseRouting();
  539. //跨域
  540. app.UseCors(AdminConsts.RequestPolicyName);
  541. //认证
  542. app.UseAuthentication();
  543. //授权
  544. app.UseAuthorization();
  545. //登录用户初始化数据权限
  546. if (appConfig.Validate.Permission)
  547. {
  548. app.Use(async (ctx, next) =>
  549. {
  550. var user = ctx.RequestServices.GetRequiredService<IUser>();
  551. if (user?.Id > 0)
  552. {
  553. var userService = ctx.RequestServices.GetRequiredService<IUserService>();
  554. await userService.GetDataPermissionAsync();
  555. }
  556. await next();
  557. });
  558. }
  559. //配置端点
  560. app.MapControllers();
  561. _hostAppOptions?.ConfigureMiddleware?.Invoke(hostAppMiddlewareContext);
  562. #region Swagger Api文档
  563. if (env.IsDevelopment() || appConfig.Swagger.Enable)
  564. {
  565. var routePrefix = appConfig.ApiUI.RoutePrefix;
  566. if (!appConfig.ApiUI.Enable && routePrefix.IsNull())
  567. {
  568. routePrefix = appConfig.Swagger.RoutePrefix;
  569. }
  570. var routePath = routePrefix.NotNull() ? $"{routePrefix}/" : "";
  571. app.UseSwagger(optoins =>
  572. {
  573. optoins.RouteTemplate = routePath + optoins.RouteTemplate;
  574. });
  575. app.UseSwaggerUI(options =>
  576. {
  577. options.RoutePrefix = appConfig.Swagger.RoutePrefix;
  578. appConfig.Swagger.Projects?.ForEach(project =>
  579. {
  580. options.SwaggerEndpoint($"/{routePath}swagger/{project.Code.ToLower()}/swagger.json", project.Name);
  581. });
  582. options.DocExpansion(Swashbuckle.AspNetCore.SwaggerUI.DocExpansion.None);//折叠Api
  583. //options.DefaultModelsExpandDepth(-1);//不显示Models
  584. if (appConfig.MiniProfiler)
  585. {
  586. options.InjectJavascript("/swagger/mini-profiler.js?v=4.2.22+2.0");
  587. options.InjectStylesheet("/swagger/mini-profiler.css?v=4.2.22+2.0");
  588. }
  589. });
  590. }
  591. #endregion Swagger Api文档
  592. _hostAppOptions?.ConfigurePostMiddleware?.Invoke(hostAppMiddlewareContext);
  593. }
  594. }