2024-10-29 14:40:07 +08:00
|
|
|
|
using LFlow.Base.Interfaces;
|
2024-10-16 11:24:10 +08:00
|
|
|
|
using LFlow.Base.Utils;
|
2024-10-31 17:48:11 +08:00
|
|
|
|
using LFlow.Cache;
|
2024-10-31 11:41:49 +08:00
|
|
|
|
using LFlow.InternalEventBus;
|
2024-11-04 15:11:14 +08:00
|
|
|
|
using Minio;
|
2024-10-31 10:38:21 +08:00
|
|
|
|
using LFlow.Middleware;
|
|
|
|
|
|
using LFlow.Middleware.Register;
|
2024-10-10 17:05:35 +08:00
|
|
|
|
using Serilog;
|
|
|
|
|
|
using Serilog.Events;
|
2024-10-09 14:45:09 +08:00
|
|
|
|
using SqlSugar;
|
2024-10-29 14:40:07 +08:00
|
|
|
|
using System.Reflection;
|
2024-11-04 15:11:14 +08:00
|
|
|
|
using Microsoft.AspNetCore.DataProtection;
|
|
|
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
|
|
using Microsoft.Extensions.Options;
|
|
|
|
|
|
using Microsoft.OpenApi.Models;
|
2024-11-06 15:56:28 +08:00
|
|
|
|
using System.Runtime;
|
|
|
|
|
|
using Microsoft.Extensions.Configuration;
|
2024-10-09 14:45:09 +08:00
|
|
|
|
|
|
|
|
|
|
namespace LFlow.Base;
|
2024-11-04 10:10:05 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
///
|
|
|
|
|
|
/// </summary>
|
2024-10-09 14:45:09 +08:00
|
|
|
|
public static class Program
|
|
|
|
|
|
{
|
2024-11-04 10:10:05 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 入口
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="args"></param>
|
2024-11-06 15:56:28 +08:00
|
|
|
|
///
|
2024-10-09 14:45:09 +08:00
|
|
|
|
public static void Main(string[] args)
|
|
|
|
|
|
{
|
2024-11-01 16:46:18 +08:00
|
|
|
|
|
2024-10-16 15:22:09 +08:00
|
|
|
|
// 先用Serilog的BootstrapLogger
|
2024-10-10 17:05:35 +08:00
|
|
|
|
Log.Logger = new LoggerConfiguration()
|
|
|
|
|
|
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
|
|
|
|
|
|
.Enrich.FromLogContext()
|
|
|
|
|
|
.WriteTo.Console()
|
|
|
|
|
|
.CreateBootstrapLogger();
|
2024-10-09 14:45:09 +08:00
|
|
|
|
|
2024-11-01 16:46:18 +08:00
|
|
|
|
ConfigDllLoader();
|
2024-10-09 14:45:09 +08:00
|
|
|
|
var builder = WebApplication.CreateBuilder(args);
|
2024-10-16 15:22:09 +08:00
|
|
|
|
// 添加到Service中
|
2024-10-10 17:05:35 +08:00
|
|
|
|
builder.Services.AddSerilog((services, lc) => lc
|
|
|
|
|
|
.ReadFrom.Configuration(builder.Configuration)
|
|
|
|
|
|
.ReadFrom.Services(services)
|
|
|
|
|
|
.Enrich.FromLogContext()
|
|
|
|
|
|
// .WriteTo.Console()
|
|
|
|
|
|
);
|
2024-11-01 16:46:18 +08:00
|
|
|
|
builder.Services.AddLogging(loggingBuilder =>
|
|
|
|
|
|
{
|
|
|
|
|
|
loggingBuilder.AddSerilog(Log.Logger, dispose: true);
|
|
|
|
|
|
});
|
2024-10-31 10:36:56 +08:00
|
|
|
|
builder.Services.AddResponseCompression();
|
|
|
|
|
|
builder.Services.AddResponseCaching();
|
2024-10-10 17:05:35 +08:00
|
|
|
|
|
2024-10-31 10:38:21 +08:00
|
|
|
|
|
2024-10-10 17:05:35 +08:00
|
|
|
|
Log.Logger.Information("LoadSubService");
|
2024-10-09 14:45:09 +08:00
|
|
|
|
builder.Services.LoadSubService();
|
2024-10-10 17:05:35 +08:00
|
|
|
|
|
2024-10-31 11:41:49 +08:00
|
|
|
|
|
2024-10-09 14:45:09 +08:00
|
|
|
|
builder.Services.AddEndpointsApiExplorer();
|
|
|
|
|
|
builder.Services.AddHttpContextAccessor();
|
2024-11-04 10:10:05 +08:00
|
|
|
|
builder.Services.AddResponseCompression();
|
2024-10-10 17:05:35 +08:00
|
|
|
|
|
|
|
|
|
|
Log.Logger.Information("ConfigureSqlSugar");
|
2024-11-04 10:10:05 +08:00
|
|
|
|
|
2024-10-09 14:45:09 +08:00
|
|
|
|
builder.Services.ConfigureSqlSugar();
|
2024-10-10 17:05:35 +08:00
|
|
|
|
|
2024-11-02 10:37:04 +08:00
|
|
|
|
builder.Services.AddControllers(c =>
|
|
|
|
|
|
{
|
|
|
|
|
|
c.Conventions.Add(new ApiExplorerGroupPerVersionConvention());
|
|
|
|
|
|
});
|
2024-11-06 15:56:28 +08:00
|
|
|
|
|
|
|
|
|
|
//注入IMinIo
|
2024-11-04 15:11:14 +08:00
|
|
|
|
builder.Services.AddSingleton<IMinioClient>
|
|
|
|
|
|
(s =>
|
2024-11-06 15:56:28 +08:00
|
|
|
|
{
|
|
|
|
|
|
var config = builder.Configuration.GetSection("MinIoConfig");
|
|
|
|
|
|
IMinioClient client = new MinioClient()
|
|
|
|
|
|
.WithEndpoint(config.GetSection("endPoint").Value)
|
|
|
|
|
|
.WithCredentials(config.GetSection("AccessKey").Value, config.GetSection("SecretKey").Value)
|
|
|
|
|
|
.WithSSL(false)
|
|
|
|
|
|
.Build();
|
|
|
|
|
|
return client;
|
|
|
|
|
|
}
|
2024-11-04 15:11:14 +08:00
|
|
|
|
);
|
|
|
|
|
|
|
2024-10-10 17:05:35 +08:00
|
|
|
|
|
2024-10-09 17:08:15 +08:00
|
|
|
|
builder.Services.AddSwaggerGen(u =>
|
|
|
|
|
|
{
|
2024-11-02 10:37:04 +08:00
|
|
|
|
|
2024-10-09 17:08:15 +08:00
|
|
|
|
u.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
|
|
|
|
|
|
{
|
|
|
|
|
|
Version = "Ver.1",
|
|
|
|
|
|
Title = "LFlow",
|
|
|
|
|
|
Description = "LFlow api test and document",
|
|
|
|
|
|
Contact = new Microsoft.OpenApi.Models.OpenApiContact
|
|
|
|
|
|
{
|
|
|
|
|
|
Name = "ling",
|
|
|
|
|
|
Email = "noemail@ling.chat"
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2024-11-02 10:37:04 +08:00
|
|
|
|
u.IncludeXmlComments("Base.xml", true);
|
|
|
|
|
|
// 获取自定义的xml目录
|
|
|
|
|
|
var xmlPath = Path.Combine(System.AppContext.BaseDirectory, "Services");
|
|
|
|
|
|
DirectoryInfo dir = new(xmlPath);
|
|
|
|
|
|
// 获取目录下的所有xml文件,并设置为swagger文档包含文件
|
|
|
|
|
|
dir.GetFiles("*.xml").ToList().ForEach(f =>
|
|
|
|
|
|
{
|
|
|
|
|
|
u.IncludeXmlComments(f.FullName, true);
|
|
|
|
|
|
|
|
|
|
|
|
u.SwaggerDoc(Path.GetFileNameWithoutExtension(f.Name), new Microsoft.OpenApi.Models.OpenApiInfo
|
|
|
|
|
|
{
|
|
|
|
|
|
Version = "Ver.1",
|
|
|
|
|
|
Title = Path.GetFileNameWithoutExtension(f.Name),
|
|
|
|
|
|
Description = "LFlow api test and document",
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
2024-10-09 17:08:15 +08:00
|
|
|
|
});
|
2024-11-04 10:10:05 +08:00
|
|
|
|
|
|
|
|
|
|
|
2024-10-18 11:29:40 +08:00
|
|
|
|
// 配置跨域策略
|
|
|
|
|
|
builder.Services.AddCors(options =>
|
|
|
|
|
|
{
|
|
|
|
|
|
options.AddPolicy("AllowAny", builder =>
|
|
|
|
|
|
{
|
|
|
|
|
|
builder.AllowAnyOrigin()
|
|
|
|
|
|
.AllowAnyMethod()
|
|
|
|
|
|
.AllowAnyHeader();
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
2024-11-01 16:46:18 +08:00
|
|
|
|
builder.Host.UseSerilog(Log.Logger);
|
|
|
|
|
|
// 注册中间件
|
|
|
|
|
|
builder.Services.RegisterMiddlewares(App.SubServiceAssembly);
|
2024-10-31 10:38:21 +08:00
|
|
|
|
|
2024-11-01 16:46:18 +08:00
|
|
|
|
// 注册内部事件总线
|
|
|
|
|
|
builder.Services.AddInternalEventBus(App.SubServiceAssembly);
|
|
|
|
|
|
// 注册自身缓存器
|
|
|
|
|
|
builder.Services.AddSelfCache();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// init App.service
|
2024-10-10 17:05:35 +08:00
|
|
|
|
App.services = builder.Services;
|
|
|
|
|
|
var app = builder.Build();
|
|
|
|
|
|
app.UseSerilogRequestLogging(options =>
|
|
|
|
|
|
{
|
2024-10-16 15:22:09 +08:00
|
|
|
|
// 配置日志级别
|
2024-10-10 17:05:35 +08:00
|
|
|
|
options.GetLevel = (httpContext, elapsed, ex) => LogEventLevel.Information;
|
|
|
|
|
|
});
|
2024-10-09 14:45:09 +08:00
|
|
|
|
app.MapControllers();
|
2024-10-18 11:30:00 +08:00
|
|
|
|
// 添加根目录映射
|
|
|
|
|
|
app.MapGet("/", async context =>
|
|
|
|
|
|
{
|
|
|
|
|
|
context.Response.ContentType = "text/html";
|
|
|
|
|
|
await context.Response.SendFileAsync(Path.Combine(app.Environment.WebRootPath, "index.html"));
|
|
|
|
|
|
});
|
2024-10-09 14:45:09 +08:00
|
|
|
|
// if (app.Environment.IsDevelopment())
|
|
|
|
|
|
{
|
|
|
|
|
|
app.UseSwagger();
|
2024-10-09 17:08:15 +08:00
|
|
|
|
app.UseSwaggerUI(u =>
|
|
|
|
|
|
{
|
|
|
|
|
|
u.DocumentTitle = "LFlow";
|
2024-11-02 10:37:04 +08:00
|
|
|
|
var xmlPath = Path.Combine(System.AppContext.BaseDirectory, "Services");
|
|
|
|
|
|
DirectoryInfo dir = new(xmlPath);
|
|
|
|
|
|
// 获取目录下的所有xml文件,并设置为swagger文档包含文件
|
|
|
|
|
|
dir.GetFiles("*.xml").ToList().ForEach(f =>
|
|
|
|
|
|
{
|
|
|
|
|
|
var progName = Path.GetFileNameWithoutExtension(f.Name);
|
|
|
|
|
|
u.SwaggerEndpoint($"/swagger/{progName}/swagger.json", progName);
|
|
|
|
|
|
});
|
2024-10-09 17:08:15 +08:00
|
|
|
|
});
|
2024-10-09 14:45:09 +08:00
|
|
|
|
}
|
2024-10-16 11:24:10 +08:00
|
|
|
|
// 在启动后调用Sqlsugar进行CodeFirst
|
|
|
|
|
|
// 挂载启动后事件
|
2024-11-04 10:10:05 +08:00
|
|
|
|
app.Services.GetRequiredService<IHostApplicationLifetime>().ApplicationStarted.Register(() =>
|
2024-10-16 11:24:10 +08:00
|
|
|
|
{
|
|
|
|
|
|
Log.Logger.Information("ApplicationStarted");
|
|
|
|
|
|
CodeFirst.InitTable();
|
2024-11-01 16:46:18 +08:00
|
|
|
|
InternalEventBus.InternalEventBus.Publish("Init", "ApplicationStarted");
|
2024-10-16 11:24:10 +08:00
|
|
|
|
});
|
2024-10-31 10:38:21 +08:00
|
|
|
|
// 启用自定义中间件
|
|
|
|
|
|
app.UseLFlowMiddleware();
|
2024-10-31 11:41:49 +08:00
|
|
|
|
// 启用内部事件总线
|
|
|
|
|
|
app.UseInternalEventBus();
|
2024-10-31 10:36:56 +08:00
|
|
|
|
// 启用缓存
|
|
|
|
|
|
app.UseResponseCaching();
|
|
|
|
|
|
// 启用压缩
|
|
|
|
|
|
app.UseResponseCompression();
|
2024-10-18 11:30:00 +08:00
|
|
|
|
// 启用静态文件支持
|
|
|
|
|
|
app.UseStaticFiles();
|
|
|
|
|
|
|
2024-10-18 11:29:40 +08:00
|
|
|
|
app.UseCors("AllowAny");
|
2024-10-09 14:45:09 +08:00
|
|
|
|
app.Run();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-04 15:11:14 +08:00
|
|
|
|
|
2024-11-04 10:10:05 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 配置SqlSugar
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="services"></param>
|
2024-10-09 14:45:09 +08:00
|
|
|
|
public static void ConfigureSqlSugar(this IServiceCollection services)
|
|
|
|
|
|
{
|
|
|
|
|
|
services.AddSingleton<ISqlSugarClient>(s =>
|
|
|
|
|
|
{
|
|
|
|
|
|
SqlSugarScope sqlSugar = new(new ConnectionConfig()
|
|
|
|
|
|
{
|
|
|
|
|
|
DbType = SqlSugar.DbType.Sqlite,
|
2024-10-10 17:05:35 +08:00
|
|
|
|
ConnectionString = "DataSource=LFlow-dev.db",
|
2024-10-09 14:45:09 +08:00
|
|
|
|
IsAutoCloseConnection = true,
|
2024-10-29 15:45:47 +08:00
|
|
|
|
InitKeyType = InitKeyType.Attribute //从实体特性中读取主键自增列信息
|
2024-10-09 14:45:09 +08:00
|
|
|
|
},
|
2024-10-16 11:24:10 +08:00
|
|
|
|
db =>
|
|
|
|
|
|
{
|
|
|
|
|
|
//单例参数配置,所有上下文生效
|
|
|
|
|
|
db.Aop.OnLogExecuting = (sql, pars) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
//获取作IOC作用域对象
|
|
|
|
|
|
var appServive = s.GetService<IHttpContextAccessor>();
|
2024-10-18 11:31:15 +08:00
|
|
|
|
var log = s.GetService<Serilog.ILogger>();
|
2024-10-16 11:24:10 +08:00
|
|
|
|
// var obj = appServive?.HttpContext?.RequestServices.GetService<Log>();
|
|
|
|
|
|
// Console.WriteLine("AOP" + obj.GetHashCode());
|
2024-10-18 11:31:15 +08:00
|
|
|
|
log?.Debug($"{appServive?.HttpContext?.Request.Path}:{sql}\r\n{pars}");
|
2024-10-16 11:24:10 +08:00
|
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
sqlSugar.DbMaintenance.CreateDatabase();
|
|
|
|
|
|
|
2024-10-09 14:45:09 +08:00
|
|
|
|
return sqlSugar;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 从子文件夹中加载DLL
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static void LoadSubService(this IServiceCollection services)
|
|
|
|
|
|
{
|
2024-11-13 13:36:09 +08:00
|
|
|
|
//TODO: 从配置文件中读取加载路径
|
2024-10-09 14:45:09 +08:00
|
|
|
|
var path = Path.Combine(AppContext.BaseDirectory, "Services");
|
|
|
|
|
|
// Console.WriteLine(path);
|
|
|
|
|
|
var files = Directory.GetFiles(path, "*.dll");
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var file in files)
|
|
|
|
|
|
{
|
2024-10-18 11:31:15 +08:00
|
|
|
|
try
|
2024-10-09 14:45:09 +08:00
|
|
|
|
{
|
2024-10-31 10:38:21 +08:00
|
|
|
|
bool isModule = false;
|
2024-10-18 11:31:15 +08:00
|
|
|
|
Log.Logger.Information($"Load file -> {file}...");
|
|
|
|
|
|
var assembly = Assembly.LoadFile(file);
|
|
|
|
|
|
var types = assembly.GetTypes();
|
|
|
|
|
|
// bool isUseController = false;
|
|
|
|
|
|
foreach (var type in types)
|
2024-10-09 14:45:09 +08:00
|
|
|
|
{
|
2024-10-18 11:31:15 +08:00
|
|
|
|
// Console.WriteLine(type);
|
|
|
|
|
|
if (type.IsClass && !type.IsAbstract)
|
2024-10-09 14:45:09 +08:00
|
|
|
|
{
|
2024-10-18 11:31:15 +08:00
|
|
|
|
var interfaces = type.GetInterfaces();
|
|
|
|
|
|
if (interfaces.Contains(typeof(IModule)))
|
|
|
|
|
|
{
|
|
|
|
|
|
Log.Logger.Information($"\tFound IModule -> {type.FullName}");
|
|
|
|
|
|
var module = Activator.CreateInstance(type) as IModule;
|
|
|
|
|
|
module?.ConfigureModule(services);
|
2024-10-31 10:38:21 +08:00
|
|
|
|
isModule = true;
|
2024-10-18 11:31:15 +08:00
|
|
|
|
}
|
2024-10-09 14:45:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-10-18 11:31:15 +08:00
|
|
|
|
// if (isUseController)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// Log.Logger.Information($"\tAdd Controllers for {assembly.FullName}");
|
|
|
|
|
|
// // 添加Controller
|
|
|
|
|
|
// services.AddControllers().AddApplicationPart(assembly);
|
|
|
|
|
|
// }
|
2024-10-31 10:38:21 +08:00
|
|
|
|
if (isModule)
|
|
|
|
|
|
{
|
|
|
|
|
|
App.SubServiceAssembly.Add(assembly);
|
|
|
|
|
|
}
|
2024-10-18 11:31:15 +08:00
|
|
|
|
Log.Logger.Information("done.\r\n");
|
2024-10-09 14:45:09 +08:00
|
|
|
|
}
|
2024-10-18 11:31:15 +08:00
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Log.Logger.Error(ex, $"Load file -> {file} error.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-10-09 14:45:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (System.Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine(ex.ToString());
|
2024-10-18 11:31:15 +08:00
|
|
|
|
|
2024-10-09 14:45:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2024-10-16 11:24:10 +08:00
|
|
|
|
|
2024-11-04 10:10:05 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 配置DLL加载器
|
2024-11-13 13:36:09 +08:00
|
|
|
|
/// 接管DLL加载过程,处理依赖问题,从当前路径和Service文件夹中加载DLL
|
2024-11-04 10:10:05 +08:00
|
|
|
|
/// </summary>
|
2024-11-01 16:46:18 +08:00
|
|
|
|
public static void ConfigDllLoader()
|
|
|
|
|
|
{
|
|
|
|
|
|
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
var assemblyName = new AssemblyName(args.Name);
|
|
|
|
|
|
|
2024-11-13 13:36:09 +08:00
|
|
|
|
// 判断是否已经被加载 避免重复加载
|
2024-11-01 16:46:18 +08:00
|
|
|
|
var loadedAssembly = AppDomain.CurrentDomain.GetAssemblies()
|
|
|
|
|
|
.FirstOrDefault(a => a.FullName == assemblyName.FullName);
|
|
|
|
|
|
if (loadedAssembly != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Log.Logger?.Information($"Assembly {assemblyName.Name} has been loaded.");
|
|
|
|
|
|
return loadedAssembly;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 从当前路径下加载
|
|
|
|
|
|
var path = Path.Combine(AppContext.BaseDirectory, $"{assemblyName.Name}.dll");
|
|
|
|
|
|
if (File.Exists(path))
|
|
|
|
|
|
{
|
|
|
|
|
|
Log.Logger?.Information($"Assembly {assemblyName.Name} has been loaded for {path}.");
|
|
|
|
|
|
return Assembly.LoadFile(path);
|
|
|
|
|
|
}
|
2024-10-16 11:24:10 +08:00
|
|
|
|
|
2024-11-01 16:46:18 +08:00
|
|
|
|
// 从Service文件夹中加载
|
|
|
|
|
|
path = Path.Combine(AppContext.BaseDirectory, "Service", $"{assemblyName.Name}.dll");
|
|
|
|
|
|
if (File.Exists(path))
|
|
|
|
|
|
{
|
|
|
|
|
|
Log.Logger?.Information($"Assembly {assemblyName.Name} has been loaded for {path}.");
|
|
|
|
|
|
return Assembly.LoadFile(path);
|
|
|
|
|
|
}
|
|
|
|
|
|
Log.Logger?.Error($"Assembly {assemblyName.Name} not found.");
|
|
|
|
|
|
return null;
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2024-10-18 11:31:15 +08:00
|
|
|
|
}
|