0
0

HostApp.cs 26 KB

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