using Autofac; using Autofac.Extensions.DependencyInjection; using BCrypt.Net; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.ResponseCompression; using Microsoft.OpenApi; using Microsoft.OpenApi.Models; using QYZH.InteractiveMagazine.Common.Extensions; using QYZH.InteractiveMagazine.Common.Helpers; using QYZH.InteractiveMagazine.Infrastructure.Autofacs; using QYZH.InteractiveMagazine.Infrastructure.Context; using QYZH.InteractiveMagazine.Infrastructure.Extensions; using QYZH.InteractiveMagazine.Infrastructure.Middleware; using QYZH.InteractiveMagazine.Infrastructure.Redis; using QYZH.InteractiveMagazine.Models.Entity; using QYZH.InteractiveMagazine.Models.Enum; using QYZH.InteractiveMagazine.Models.Settings; using QYZH.InteractiveMagazine.Repository; using QYZH.InteractiveMagazine.Repository.Core; using Serilog; using SqlSugar.IOC; using Swashbuckle.AspNetCore.SwaggerGen; using Swashbuckle.AspNetCore.SwaggerUI; using System.Text.Json.Serialization; using Yitter.IdGenerator; var builder = WebApplication.CreateBuilder(args); // 加载勋章规则独立配置文件 builder.Configuration.AddJsonFile("medal-rule-config.json", optional: false, reloadOnChange: true); // 初始化雪花ID生成器 YitIdHelper.SetIdGenerator(new IdGeneratorOptions() { WorkerId = 1 }); // autofac注入 允许使用autofac作为DI容器 builder.UseAutofac(); builder.InitSqlSugarDb(new IocConfig() { ConfigId = 0, DbType = IocDbType.MySql, ConnectionString = builder.Configuration.GetConnectionString("DefaultConnection"), IsAutoCloseConnection = true, }); // 消除Error unprotecting the session cookie警告 builder.Services.AddDataProtection() .PersistKeysToFileSystem(new DirectoryInfo(Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + "DataProtection")); //redis builder.Services.AddCSRedisCacheExtension(builder.Configuration.GetSection("RedisSettings")); // 配置Serilog Log.Logger = new LoggerConfiguration() .ReadFrom.Configuration(builder.Configuration) .Enrich.FromLogContext() .CreateLogger(); builder.Host.UseSerilog(); builder.Services.AddControllers(options => { options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true;//Required 不作为必填 options.Filters.Add();//添加自定义模型验证 }) .AddJsonOptions(options => { // 配置 JSON 不区分大小写(支持 camelCase 和 PascalCase) options.JsonSerializerOptions.PropertyNameCaseInsensitive = true; // 配置返回时间格式转换 options.JsonSerializerOptions.Converters.Add(new JsonConverterUtil.DateTimeConverter()); options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles; }).ConfigureApiBehaviorOptions(opt => opt.SuppressModelStateInvalidFilter = true);//关闭默认模型验证 builder.Services.AddEndpointsApiExplorer(); // 跨域配置 builder.Services.AddDataProtection().UseEphemeralDataProtectionProvider(); builder.AddCorsRegister(); //builder.Services.AddSession(); builder.Services.AddHttpClient(); // 注册 Swagger 文档 builder.Services.AddSwaggerGen(option => { var xmlFile = $"{AppDomain.CurrentDomain.FriendlyName}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); var modelXml = Path.Combine(AppContext.BaseDirectory, $"QYZH.InteractiveMagazine.Models.xml"); Enum.GetValues().ToList().ForEach(version => { // 配置文档信息 option.SwaggerDoc(version.ToString(), new OpenApiInfo { Title = AppDomain.CurrentDomain.FriendlyName, Version = "互动期刊接口文档", Description = $"{version.GetDescription()}接口,Last Modify Time:{new FileInfo(xmlPath).LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss")}" }); }); // 配置接口路径排序 option.OrderActionsBy(o => o.RelativePath); if (File.Exists(xmlPath)) option.IncludeXmlComments(xmlPath, true); if (File.Exists(modelXml)) option.IncludeXmlComments(modelXml, true); option.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme() { Description = "请输入 Token,格式为 Bearer Token", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.ApiKey, BearerFormat = "JWT", Scheme = "Bearer" }); option.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] { } } }); // 过滤文档/路径/方法筛选接口的响应结果 option.DocInclusionPredicate((docName, apiDesc) => { // 方式 1:将接口的 [ApiExplorerSettings(GroupName = "xxx")] 特性匹配 if (!apiDesc.TryGetMethodInfo(out var methodInfo)) return false; var groupName = methodInfo.DeclaringType? .GetCustomAttributes(true) .OfType() .FirstOrDefault()? .GroupName; // 匹配当前文档(分组)则显示 return groupName == docName; }); }); builder.Services.AddInfrastructureServices(builder.Configuration, builder.Environment); //注册 HttpContextAccessor builder.Services.AddHttpContextAccessor(); builder.Services.AddScoped(typeof(BaseRepository<>)); // 注册勋章规则配置 builder.Services.Configure(builder.Configuration.GetSection("MedalRuleConfig")); // 添加CORS builder.Services.AddCors(options => { options.AddPolicy("AllowAll", policy => { policy.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader(); }); }); #region 配置数据压缩选项 // 1.首先配置压缩选项的Options> builder.Services.Configure(options => { options.Level = System.IO.Compression.CompressionLevel.Optimal; }); builder.Services.Configure(options => { options.Level = System.IO.Compression.CompressionLevel.Fastest; }); // 2.在服务容器中注册响应压缩服务 builder.Services.AddResponseCompression(options => { // 可以在这里进行详细配置 options.EnableForHttps = true; // 启用对HTTPS响应的压缩(请注意安全风险) options.Providers.Add(); options.Providers.Add(); //指定哪些类型的响应应该被压缩。默认列表包含常见的文本类类型,如 text/html, text/css, application/javascript, application/json, text/plain等 options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(["image/svg+xml", "application/json", "text/plain"]); }); #endregion var app = builder.Build(); { app.UseSwagger(); app.UseSwaggerUI(c => { // 根据版本名称倒序 遍历展示 Enum.GetValues().OrderBy(e => e).ToList().ForEach(version => { c.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"{version.GetDescription()}接口"); }); c.DocExpansion(DocExpansion.None); // ->修改界面打开时自动折叠 }); } app.UseServiceContext(); app.UseHttpsRedirection(); app.UseCors("AllowAll"); app.UseMiddleware(); app.UseMiddleware(); app.UseMiddleware(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();