gx 配置
This commit is contained in:
1 parent
0e1620c1f9
commit
c732ecb1d2
7 files changed
+166
-16
No files matched your search
@@ -1,14 +1,17 @@
|
||||
using MAX.Framework.Interfaces;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Configuration.Json;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MAX.Framework.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// 宿主(Program.cs)入口:模块两阶段装配。
|
||||
/// 宿主(Program.cs)入口:模块两阶段装配 + 模块自己的配置文件。
|
||||
/// <code>
|
||||
/// var builder = WebApplication.CreateBuilder(args);
|
||||
/// builder.AddStoreHub(); // 阶段一:服务注册(自动执行所有 IModule.AddModule)
|
||||
/// builder.AddStoreHub(); // 阶段一:加载各模块配置文件 + 自动执行所有 IModule.AddModule
|
||||
///
|
||||
/// var app = builder.Build();
|
||||
/// // ... 宿主自己的中间件、认证、端点 ...
|
||||
@@ -20,12 +23,27 @@ namespace MAX.Framework.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// 在 <see cref="WebApplicationBuilder"/> 上注册应用框架服务:
|
||||
/// 等价于 <c>builder.Services.AddStoreHub(builder.Configuration, builder.Environment)</c>,
|
||||
/// 区别是会把配置与环境一起包装成 <see cref="ModuleContext"/> 交给各模块。
|
||||
/// <list type="number">
|
||||
/// <item>发现所有 <see cref="IModule"/>;</item>
|
||||
/// <item>把每个模块声明的 <see cref="IModule.ConfigurationFile"/> 并入宿主配置树(宿主 appsettings.json 不需要放模块的配置);</item>
|
||||
/// <item>再执行 <c>builder.Services.AddStoreHub(builder.Configuration, builder.Environment)</c>。</item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public static WebApplicationBuilder AddStoreHub(this WebApplicationBuilder builder)
|
||||
{
|
||||
builder.Services.AddStoreHub(builder.Configuration, builder.Environment);
|
||||
IEnumerable<Assembly> assemblies = ServiceCollectionExtensions.GetApplicationAssemblies();
|
||||
|
||||
// 同一个类可能同时实现 IStartup 与 IModule,这里缓存实例,保证后面两个阶段拿到的是同一个对象
|
||||
Dictionary<Type, object> instances = [];
|
||||
ModuleRegistry modules = ServiceCollectionExtensions.DiscoverModules(assemblies, instances);
|
||||
|
||||
// 必须在跑 AddModule 之前并入,模块注册时才读得到自己的配置节
|
||||
foreach (IModule module in modules.Modules)
|
||||
{
|
||||
AddModuleConfigurationFile(builder.Configuration, module);
|
||||
}
|
||||
|
||||
builder.Services.AddStoreHubCore(assemblies, modules, instances, builder.Configuration, builder.Environment);
|
||||
return builder;
|
||||
}
|
||||
|
||||
@@ -57,5 +75,51 @@ namespace MAX.Framework.DependencyInjection
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 把模块自己的配置文件并进宿主配置:插在 appsettings*.json 之后、环境变量/命令行之前,
|
||||
/// 这样模块配置能覆盖宿主 appsettings.json,同时仍然允许用环境变量/命令行覆盖它。
|
||||
/// </summary>
|
||||
private static void AddModuleConfigurationFile(IConfigurationBuilder configuration, IModule module)
|
||||
{
|
||||
string? fileName = module.ConfigurationFile;
|
||||
if (string.IsNullOrWhiteSpace(fileName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string path = Path.IsPathRooted(fileName)
|
||||
? fileName
|
||||
: Path.Combine(AppContext.BaseDirectory, fileName);
|
||||
|
||||
JsonConfigurationSource source = new()
|
||||
{
|
||||
Path = path,
|
||||
Optional = true, // 文件不存在时不报错(模块没配就是没有)
|
||||
ReloadOnChange = true // 允许改配置不重启(与 appsettings.json 行为一致)
|
||||
};
|
||||
source.ResolveFileProvider();
|
||||
|
||||
IList<IConfigurationSource> sources = configuration.Sources;
|
||||
int index = sources.Count;
|
||||
|
||||
// 找到最后一个 appsettings*.json,插到它后面
|
||||
for (int i = sources.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (sources[i] is FileConfigurationSource file
|
||||
&& Path.GetFileName(file.Path).StartsWith("appsettings", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
index = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sources.Insert(index, source);
|
||||
|
||||
if (configuration is IConfigurationRoot root)
|
||||
{
|
||||
root.Reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user