using System; using System.Configuration; using System.Data; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.Serialization; using System.Text.Json; using System.Text.Json.Serialization; using System.Text.RegularExpressions; using System.Threading.Tasks; using DocumentFormat.OpenXml.InkML; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Internal; 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 Serilog.Formatting.Json; 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.Json; using Volo.Abp.Json.SystemTextJson.JsonConverters; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.Timing; 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 { static ModuleBase() { AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true); } public override void ConfigureServices(ServiceConfigurationContext context) { var cfg = context.Services.GetConfiguration(); ServiceConfigurationContext.SetConsoleTitleOfWebApp(Assembly.GetEntryAssembly().GetName().Name); LimitedResultRequestDto.MaxMaxResultCount = 100000; //接口请求限制 context.Services.Configure(options => { options.Limits.MaxRequestBodySize = int.MaxValue; }); context.Services.Configure(x => { x.ValueLengthLimit = int.MaxValue; x.MultipartBodyLengthLimit = int.MaxValue; }); //context.Services.AddAgileConfig(); PreConfigureServices(context); ConfigureAntiForgery(); ConfigureLocalizationServices(); ConfigureAuthentication(); ConfigureDistributedCache(); ConfigureDatabase(context, cfg); ConfigureHttpClientProxies(); ConfigureAutoMapper(); ConfigureLocalizationServices(); ConfigureAutoApiControllers(); ConfigureSwaggerServices(); ConfigureAddCors(); Configure(); SetFormLimit(); ConfigureExceptionHanding(); } private void ConfigureDatabase(ServiceConfigurationContext context, IConfiguration cfg) { var db = cfg.GetValue("Database", "SQLite"); SequentialGuidType? sequentialGuidType = null; if (db == "MySQL" || db == "PostgreSql") { sequentialGuidType = SequentialGuidType.SequentialAsString; } else if (db == "SQLServer") { sequentialGuidType = SequentialGuidType.SequentialAtEnd; } else if (db == "Oracle") { sequentialGuidType = SequentialGuidType.SequentialAsBinary; } context.Services.Configure(o => o.DefaultSequentialGuidType = sequentialGuidType); Configure(options => { if (db == "MySQL") { options.UseMySQL(); } else if (db == "SQLServer") { options.UseSqlServer(); } else if (db == "Oracle") { options.UseOracle(); } else if (db == "PostgreSql") { options.UseNpgsql(); } else { options.UseSqlite(); } }); } public override async Task ConfigureServicesAsync(ServiceConfigurationContext context) { await base.ConfigureServicesAsync(context).ConfigureAwait(false); } public virtual void CreateDatabase(ApplicationInitializationContext context) where TEfCoreDbContext : IEfCoreDbContext { //Console.WriteLine($"应用版本:{Assembly.GetEntryAssembly().GetFileVersion()}"); ////if (!context.GetEnvironment().IsDevelopment()) ////{ //// Console.WriteLine($"生产模式不执行数据库初始化"); //// return; ////} //using var scope = context.ServiceProvider.CreateScope(); //var contextName = typeof(TEfCoreDbContext).Name; ////var uowManager = scope.ServiceProvider.GetRequiredService(); ////using var uow = uowManager.Begin(); //var provider = scope.ServiceProvider.GetRequiredService>(); ////using var dbContext = provider.GetDbContextAsync().Result; //using var dbContext = scope.ServiceProvider.GetRequiredService(typeof(TEfCoreDbContext)) as DbContext; //dbContext.Database.SetCommandTimeout(TimeSpan.FromMinutes(10)); //var dbCreator = dbContext.GetService() as RelationalDatabaseCreator; //var sql = dbCreator.GenerateCreateScript(); //sql = dbContext.Database.ProviderName.Contains("SqlServer") ? Regex.Replace(sql, ";\\s+GO\\s", " ") : sql; //var md5 = sql.Md5(); //var path = Path.Combine(Directory.GetCurrentDirectory(), "scripts"); //Directory.CreateDirectory(path); //using var sw = File.CreateText(Path.Combine(path, $"db.{dbContext.Database.ProviderName}.{contextName}.sql")); //sw.Write(sql); //Console.WriteLine($"{contextName} 初始化开始"); //Console.WriteLine($"ConnectionString:{dbContext.Database.GetConnectionString()}"); ////创建数据库 //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(); ////conn.Dispose(); //if (hash == null) //{ // try // { // //dbContext.Database.BeginTransaction(); // dbContext.Database.ExecuteSqlRaw(sql); // dbContext.Database.ExecuteSqlRaw($"INSERT INTO EFDbContext VALUES ('{contextName}', '{md5}');"); // context.ServiceProvider // .GetRequiredService() // .SeedAsync() // .Wait(); // //dbContext.Database.CommitTransaction(); // Console.WriteLine($"{contextName} 初始化成功"); // } // catch (Exception ex) // { // //dbContext.Database.RollbackTransaction(); // var message = $"{contextName} 初始化失败:{ex.Message}"; // Console.WriteLine(message); // Console.WriteLine(ex.ToString()); // throw new Exception(message, ex); // } // finally // { // Console.WriteLine($"{contextName} 初始化结束"); // } //} //else //{ // Console.WriteLine($"{contextName} 数据库结构{(hash.ToString() == md5 ? "正常" : "已过时")}"); //} //uow.CompleteAsync(); //conn.Close(); //conn.Dispose(); } 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("CorsPolicy"); 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() { //todo 解决时间 // ServiceConfigurationContext.Services.AddTransient(); } protected virtual void ConfigureAddCors() { var origins = ServiceConfigurationContext.Services.GetConfiguration().GetSection("App:CorsOrigins").Get() ?? Array.Empty(); Console.WriteLine($"CORS Origins:{string.Concat(origins)}"); ServiceConfigurationContext.Services.AddCors(options => { options.AddPolicy("CorsPolicy", builder => { builder.SetIsOriginAllowed(_ => true).AllowAnyMethod().AllowAnyHeader().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(IConfiguration configuration) { Configure(options => { options.UseDatabase(configuration); }); } 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.SchemaFilter(); 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); AppDomain.CurrentDomain.GetAssemblies() .Where(o => o.GetName().Name.StartsWith(nameof(Win_in)) && o.GetName().Name.EndsWith(".Application")) .Select(o => Path.Combine(Path.GetDirectoryName(o.Location), $"{Path.GetFileNameWithoutExtension(o.Location)}.xml")) .Where(o => File.Exists(o)) .ForEach(o => options.IncludeXmlComments(o)); }); } protected virtual void SetFormLimit() { ServiceConfigurationContext.Services.Configure(options => { options.ValueCountLimit = int.MaxValue; // 5000 items max options.ValueLengthLimit = 1024 * 1024 * 1000; // 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; }); } /// /// 为了处理abp的时间存入redis 在win环境读取出来报错 /// public class ConvertAbpJson : IJsonSerializer { public T Deserialize(string jsonString, bool camelCase = true) { return System.Text.Json.JsonSerializer.Deserialize(jsonString, GetOptions(camelCase)); } public object Deserialize(Type type, string jsonString, bool camelCase = true) { return System.Text.Json.JsonSerializer.Deserialize(jsonString, type, GetOptions(camelCase)); } public string Serialize(object obj, bool camelCase = true, bool indented = false) { return System.Text.Json.JsonSerializer.Serialize(obj, GetOptions(camelCase, indented)); } private System.Text.Json.JsonSerializerOptions GetOptions(bool camelCase = true, bool indented = false) { return new System.Text.Json.JsonSerializerOptions { PropertyNameCaseInsensitive = camelCase, WriteIndented = indented, ReferenceHandler = ReferenceHandler.IgnoreCycles }; } } }