using System; using System.Data; using System.IO; using System.Linq; using System.Reflection; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using Microsoft.OpenApi.Models; using NUglify.Helpers; using StackExchange.Redis; using Swashbuckle.AspNetCore.SwaggerGen; using Volo.Abp; using Volo.Abp.Application.Dtos; using Volo.Abp.AspNetCore.ExceptionHandling; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.AntiForgery; using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Bundling; using Volo.Abp.AutoMapper; using Volo.Abp.Caching; using Volo.Abp.Content; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.Guids; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.Uow; using Win_in.Sfs.Shared.Application; using Win_in.Sfs.Shared.Application.Contracts.ExportAndImport; using Win_in.Sfs.Shared.Domain.Shared; namespace Win_in.Sfs.Shared.Host; public abstract class ModuleBase : AbpModule where T : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { ServiceConfigurationContext.SetConsoleTitleOfWebApp(Assembly.GetEntryAssembly().GetName().Name); LimitedResultRequestDto.MaxMaxResultCount = 100000; context.Services.Configure(o => o.DefaultSequentialGuidType = SequentialGuidType.SequentialAsString); PreConfigureServices(context); ConfigureAntiForgery(); ConfigureLocalizationServices(); ConfigureAuthentication(); ConfigureDistributedCache(); ConfigureDbContext(); ConfigureHttpClientProxies(); ConfigureAutoMapper(); ConfigureLocalizationServices(); ConfigureAutoApiControllers(); ConfigureSwaggerServices(); ConfigureAddCors(); SetFormLimit(); ConfigureExceptionHanding(); context.Services.AddAgileConfig(); } public override async Task ConfigureServicesAsync(ServiceConfigurationContext context) { await base.ConfigureServicesAsync(context).ConfigureAwait(false); } public virtual void CreateDatabase(ApplicationInitializationContext context) where TEfCoreDbContext : IEfCoreDbContext { //if (!context.GetEnvironment().IsDevelopment()) //{ // Console.WriteLine($"生产模式不执行数据库初始化"); // return; //} var contextName = typeof(TEfCoreDbContext).Name; using var scope = context.ServiceProvider.CreateScope(); var uowManager = scope.ServiceProvider.GetRequiredService(); using var uow = uowManager.Begin(); var provider = scope.ServiceProvider.GetRequiredService>(); using var dbContext = provider.GetDbContextAsync().Result; var dbCreator = dbContext.GetService() as RelationalDatabaseCreator; var sql = dbCreator.GenerateCreateScript(); var md5 = sql.Md5(); var path = Path.Combine(Directory.GetCurrentDirectory(), "scripts"); Directory.CreateDirectory(path); using var sw = File.CreateText(Path.Combine(path, $"db.{contextName}.sql")); sw.Write(sql); Console.WriteLine($"{contextName} 初始化开始"); //创建数据库 if (!dbCreator.Exists()) { dbCreator.Create(); var createSql = "CREATE TABLE `EFDbContext`(`Id` varchar(255) NOT NULL,`Hash` varchar(255) NOT NULL,PRIMARY KEY (`Id`));"; dbContext.Database.ExecuteSqlRaw(createSql); } // 查询当前DbContext是否已经初始化 using var conn = dbContext.Database.GetDbConnection(); var cmd = conn.CreateCommand(); conn.Open(); cmd.CommandText = $"SELECT `Hash` FROM EFDbContext where `Id`='{contextName}'"; var hash = cmd.ExecuteScalar(); conn.Close(); if (hash == null) { try { dbContext.Database.BeginTransaction(); dbContext.Database.ExecuteSqlRaw(sql); dbContext.Database.ExecuteSqlRaw($"INSERT INTO `EFDbContext` VALUES ('{contextName}', '{md5}');"); dbContext.Database.CommitTransaction(); context.ServiceProvider .GetRequiredService() .SeedAsync() .Wait(); Console.WriteLine($"{contextName} 初始化成功"); } catch (Exception ex) { dbContext.Database.RollbackTransaction(); throw new Exception($"{contextName} 初始化失败:{ex.Message}", ex); } finally { Console.WriteLine($"{contextName} 初始化结束"); } } else { Console.WriteLine($"{contextName} 数据库结构{(hash.ToString() == md5 ? "正常" : "已过时")}"); } uow.CompleteAsync(); } public override void OnApplicationInitialization(ApplicationInitializationContext context) { // base.OnApplicationInitialization(context); var app = context.GetApplicationBuilder(); app.UseDeveloperExceptionPage(); app.UseAbpRequestLocalization(); app.UseCorrelationId(); app.UseStaticFiles(); app.UseRouting(); app.UseCors(); app.UseAuthentication(); app.UseJwtTokenMiddleware(); app.UseUnitOfWork(); app.UseAuthorization(); app.UseSwagger(); app.UseSwaggerUI(options => { var apiDescriptionGroups = context.ServiceProvider.GetRequiredService().ApiDescriptionGroups.Items; foreach (var description in apiDescriptionGroups) { if (description.GroupName is not null) { options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName); } else { options.SwaggerEndpoint($"/swagger/Default/swagger.json", "Default"); } } }); app.UseAuditing(); app.UseAbpSerilogEnrichers(); app.UseConfiguredEndpoints(); context.ServiceProvider.InitSettings(); UseMultiTenancy(context); } protected virtual void Configure() { } protected virtual void ConfigureAddCors() { var origins = ServiceConfigurationContext.Services.GetConfiguration().GetSection("App:CorsOrigins").Get() ?? Array.Empty(); ServiceConfigurationContext.Services.AddCors(options => { options.AddDefaultPolicy(builder => { builder .WithOrigins( origins .Select(o => o.RemovePostFix("/")) .ToArray() ) //.AllowAnyOrigin()//允许所有跨域 .WithAbpExposedHeaders() .SetIsOriginAllowedToAllowWildcardSubdomains() .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials();//按配置文件中 跨域 }); }); } protected virtual void ConfigureAntiForgery() { Configure(options => { options.TokenCookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax; options.TokenCookie.Expiration = TimeSpan.FromDays(365); options.AutoValidateIgnoredHttpMethods.Add("POST"); }); } protected virtual void ConfigureAuditing() { } protected virtual void ConfigureAuthentication() { var configuration = ServiceConfigurationContext.Services.GetConfiguration(); ServiceConfigurationContext.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.Authority = configuration["AuthServer:Authority"]; options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]); options.Audience = configuration["AuthServer:Audience"]; }); var isAlwaysAllowAuthorization = configuration.GetValue("AlwaysAllowAuthorization"); if (isAlwaysAllowAuthorization) { //绕过授权服务,用于测试 ServiceConfigurationContext.Services.AddAlwaysAllowAuthorization(); } } protected virtual void ConfigureAutoApiControllers() { Configure(options => { AppDomain.CurrentDomain.GetAssemblies() .Where(assembly => assembly.FullName.StartsWith("Win_in.Sfs")) .ForEach(assembly => options.ConventionalControllers.Create(assembly)); }); } protected virtual void ConfigureAutoMapper() { Configure(options => { options.AddMaps(); }); } protected virtual void ConfigureBundles() { Configure(options => { options.StyleBundles.Configure( BasicThemeBundles.Styles.Global, bundle => { bundle.AddFiles("/global-styles.css"); } ); }); } protected virtual void ConfigureDbContext() { } protected virtual void ConfigureDistributedCache() { var evn = ServiceConfigurationContext.Services.GetHostingEnvironment(); var cfg = ServiceConfigurationContext.Services.GetConfiguration(); Configure(options => { options.KeyPrefix = cfg["Redis:KeyPrefix"]; }); if (!evn.IsDevelopment()) { var redis = ConnectionMultiplexer.Connect(cfg["Redis:Configuration"]); ServiceConfigurationContext.Services .AddDataProtection() .PersistKeysToStackExchangeRedis(redis, $"{Assembly.GetEntryAssembly().GetName().Name}-Protection-Keys"); } } protected virtual void ConfigureExceptionHandling() { Configure(options => { options.SendExceptionsDetailsToClients = true; //向前端返回完整错误日志 }); } protected virtual void ConfigureHttpClientProxies() { } protected virtual void ConfigureLocalizationServices() { Configure(options => { options.Languages.Add(new LanguageInfo("en", "en", "English")); options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); }); } protected virtual void ConfigureSwaggerServices() { var services = ServiceConfigurationContext.Services; var cfg = ServiceConfigurationContext.Services.GetConfiguration(); var name = Assembly.GetEntryAssembly().GetName().Name; var urlBase = cfg["AuthServer:Authority"].EnsureEndsWith('/'); services.AddSingleton(); services.AddTransient, SwaggerConfigureOptions>(); services.AddSwaggerGen(options => { var schemaFactory = () => new OpenApiSchema { Type = "string", Format = "binary" }; options.MapType(schemaFactory); options.MapType(schemaFactory); // options.DocumentFilter(); options.OperationFilter(); options.AddSecurityDefinition(nameof(SecuritySchemeType.Http), new OpenApiSecurityScheme { Type = SecuritySchemeType.Http, Scheme = "bearer", BearerFormat = "JWT", In = ParameterLocation.Header, }); options.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = nameof(SecuritySchemeType.Http) } }, Array.Empty() } }); options.SwaggerDoc("v1", new OpenApiInfo { Title = $"{name} API", Version = "v1" }); options.DocInclusionPredicate((docName, description) => true); options.CustomSchemaIds(type => type.FullName); options.DocInclusionPredicate((docName, api) => api.GroupName == null || api.GroupName == docName); }); } protected virtual void SetFormLimit() { ServiceConfigurationContext.Services.Configure(options => { options.ValueCountLimit = 5000; // 5000 items max options.ValueLengthLimit = 1024 * 1024 * 100; // 100MB max len form data }); } protected virtual void UseMultiTenancy(ApplicationInitializationContext context) { if (Convert.ToBoolean(context.GetConfiguration().GetValue("IsMultiTenancy", false))) { context.GetApplicationBuilder().UseMultiTenancy(); } } private void ConfigureExceptionHanding() { Configure(options => { options.SendExceptionsDetailsToClients = true; }); } }