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.
499 lines
19 KiB
499 lines
19 KiB
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<T> : 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<KestrelServerOptions>(options =>
|
|
{
|
|
options.Limits.MaxRequestBodySize = int.MaxValue;
|
|
});
|
|
context.Services.Configure<FormOptions>(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<AbpSequentialGuidGeneratorOptions>(o => o.DefaultSequentialGuidType = sequentialGuidType);
|
|
Configure<AbpDbContextOptions>(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<TEfCoreDbContext>(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<IUnitOfWorkManager>();
|
|
////using var uow = uowManager.Begin();
|
|
//var provider = scope.ServiceProvider.GetRequiredService<IDbContextProvider<TEfCoreDbContext>>();
|
|
////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<IRelationalDatabaseCreator>() 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<IDataSeeder>()
|
|
// .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<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()
|
|
{
|
|
//todo 解决时间
|
|
// ServiceConfigurationContext.Services.AddTransient<IJsonSerializer,ConvertAbpJson>();
|
|
|
|
}
|
|
|
|
protected virtual void ConfigureAddCors()
|
|
{
|
|
var origins = ServiceConfigurationContext.Services.GetConfiguration().GetSection("App:CorsOrigins").Get<string[]>() ?? Array.Empty<string>();
|
|
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<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(IConfiguration configuration)
|
|
{
|
|
Configure<AbpDbContextOptions>(options =>
|
|
{
|
|
options.UseDatabase(configuration);
|
|
});
|
|
}
|
|
|
|
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.SchemaFilter<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);
|
|
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<FormOptions>(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<AbpExceptionHandlingOptions>(options =>
|
|
{
|
|
options.SendExceptionsDetailsToClients = true;
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 为了处理abp的时间存入redis 在win环境读取出来报错
|
|
/// </summary>
|
|
public class ConvertAbpJson : IJsonSerializer
|
|
{
|
|
public T Deserialize<T>(string jsonString, bool camelCase = true)
|
|
{
|
|
return System.Text.Json.JsonSerializer.Deserialize<T>(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
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|