You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

387 lines
14 KiB

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<T> : AbpModule where T : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
ServiceConfigurationContext.SetConsoleTitleOfWebApp(Assembly.GetEntryAssembly().GetName().Name);
LimitedResultRequestDto.MaxMaxResultCount = 100000;
context.Services.Configure<AbpSequentialGuidGeneratorOptions>(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<TEfCoreDbContext>(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<IUnitOfWorkManager>();
using var uow = uowManager.Begin();
var provider = scope.ServiceProvider.GetRequiredService<IDbContextProvider<TEfCoreDbContext>>();
using var dbContext = provider.GetDbContextAsync().Result;
var dbCreator = dbContext.GetService<IRelationalDatabaseCreator>() 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<IDataSeeder>()
.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<IApiDescriptionGroupCollectionProvider>().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<string[]>() ?? Array.Empty<string>();
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<AbpAntiForgeryOptions>(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<bool>("AlwaysAllowAuthorization");
if (isAlwaysAllowAuthorization)
{
//绕过授权服务,用于测试
ServiceConfigurationContext.Services.AddAlwaysAllowAuthorization();
}
}
protected virtual void ConfigureAutoApiControllers()
{
Configure<AbpAspNetCoreMvcOptions>(options =>
{
AppDomain.CurrentDomain.GetAssemblies()
.Where(assembly => assembly.FullName.StartsWith("Win_in.Sfs"))
.ForEach(assembly => options.ConventionalControllers.Create(assembly));
});
}
protected virtual void ConfigureAutoMapper()
{
Configure<AbpAutoMapperOptions>(options =>
{
options.AddMaps<T>();
});
}
protected virtual void ConfigureBundles()
{
Configure<AbpBundlingOptions>(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<AbpDistributedCacheOptions>(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<AbpExceptionHandlingOptions>(options =>
{
options.SendExceptionsDetailsToClients = true; //向前端返回完整错误日志
});
}
protected virtual void ConfigureHttpClientProxies()
{
}
protected virtual void ConfigureLocalizationServices()
{
Configure<AbpLocalizationOptions>(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<IExportImportService, ClosedXmlExportImportService>();
services.AddTransient<IConfigureOptions<SwaggerGenOptions>, SwaggerConfigureOptions>();
services.AddSwaggerGen(options =>
{
var schemaFactory = () => new OpenApiSchema
{
Type = "string",
Format = "binary"
};
options.MapType<RemoteStreamContent>(schemaFactory);
options.MapType<IRemoteStreamContent>(schemaFactory);
//
options.DocumentFilter<SwaggerFilter>();
options.OperationFilter<SwaggerFilter>();
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<string>()
}
});
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<FormOptions>(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<AbpExceptionHandlingOptions>(options =>
{
options.SendExceptionsDetailsToClients = true;
});
}
}