ASP.NET 核心通过 HTTP 接收自定义配置以配置 Kestrel
ASP.NET Core receive custom config via HTTP to configure Kestrel
这感觉像是一个简单的问题,但在我所有的搜索中,我仍然没有找到适合我的解决方案。可能是另一种找不到我想要的东西的情况,因为我没有搜索正确的 'thing',但我们在这里..
我有一个 C# Web API 程序,我想在其中从配置对象配置 kestrel 服务器。
我通过 rest 调用将此配置接收到我的服务中,进入 CustomConfig
对象。我可以在 Program.cs
或 Startup.cs
中获取此配置对象,但由于我不想重复自己并进行额外的调用,所以我不想在这两个地方都这样做。
我的偏好是在 Startup.cs
中获取配置,因为这是我的其余配置代码所在的位置,也是我已经在使用我的 CustomConfig
对象的位置。但是,我找不到一种方法来配置 kestrel 服务器以使用我给它的证书(在 Startup.cs 中),我也看不到将此配置从 Startup.cs
注入 Startup.cs
的方法=13=].
在其他项目中,我将 PFX 文件的位置作为环境变量传递:ASPNETCORE_Kestrel__Certificates__Default__Path
(在这种情况下,无需额外的代码配置,一切正常),但在这个项目中,所有配置都必须通过 rest 检索打电话,所以这不是这里的一个选项。
我目前拥有所有东西 运行,但只能通过调用 rest 两次来获取配置。当前配置 kestrel 的实现是将 PFX 存储在 CustomConfig
中作为 base64 字符串,并在 Program.cs
:
中配置
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
CustomConfig config = CustomConfig() // <- I receive config here
webBuilder.UseStartup<Startup>();
webBuilder.UseKestrel(options =>
{
options.ConfigureHttpsDefaults(d =>
{
byte[] pfxBytes = Convert.FromBase64String(config.Base64PFXBytes);
d.ServerCertificate = new X509Certificate2(pfxBytes, "sslKey");
});
});
});
}
总结一下..
- 我有一个
CustomConfig
对象,用于在 Startup.cs
中配置服务
- 我想从
CustomConfig
配置我的 Kestrel 服务器
所以我正在寻求帮助:
- 让 Kestrel 在
Startup.cs
内使用我的 PFX
- 将
CustomConfig
对象从 Program.cs
传递到 Startup.cs
希望这是有道理的。为了清楚起见,欢迎提出任何和所有解决方案/其他问题!
提前致谢!
ASP.NET 核心使用 IConfiguration
接口抽象配置。不细说,收集
来自各种 IConfigurationSource
的配置并将它们叠加在一起,这让我们可以覆盖
通过使用相同的键定义在另一个源中定义的设置。
1。实施 IConfigurationSource
让我们实施一个 IConfigurationSource
。我们可以使用 ConfigurationSource
摘要 class 作为我们的起点。出色地
使用内存中实现,然后切换到远程源。
class RemoteConfigurationSource : IConfigurationSource
{
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new RemoteConfigurationProvider(_options);
}
private class RemoteConfigurationProvider : ConfigurationProvider
{
public override void Load()
{
// TODO: fetch data from the API
var remoteConfig = new Dictionary<string, string>
{
{ "CertificateOptions:PfxBase64", "MIIKkQIBAz....gfQ" },
{ "CertificateOptions:Password", "secret" },
};
Data = remoteConfig;
}
}
}
然后将其添加到 ConfigureHostConfiguration
回调中的配置生成器:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureHostConfiguration(builder =>
{
// add new source
builder.AddRemoteConfiguration();
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>().UseKestrel((context, options) =>
{
var certificateOptions = context.Configuration
.GetSection(KestrelCertificateOptions.ConfigurationKey)
.Get<KestrelCertificateOptions>();
options.ConfigureHttpsDefaults(adapterOptions =>
adapterOptions.ServerCertificate = certificateOptions.Certificate);
});
});
}
public static class ConfigurationBuilderExtensions
{
public static IConfigurationBuilder AddRemoteConfiguration(this IConfigurationBuilder builder) =>
builder.Add(new RemoteConfigurationSource());
}
class KestrelCertificateOptions
{
public const string ConfigurationKey = "CertificateOptions";
public string PfxBase64 { get; set; }
public string Password { get; set; }
public X509Certificate2 Certificate => new X509Certificate2(Convert.FromBase64String(PfxBase64), Password);
}
当我们 运行 应用程序时,ASP.NET 核心将加载并使用我们的内存配置。
2。从 API
获取配置数据
现在让我们从远程 API 获取配置。它需要 return 配置值,部分名称以分隔
带有冒号 :
。这是与 JSON 相同的配置,在 CertificateOptions
部分下归档:
{
"CertificateOptions:PfxBase64": "MII....oCAgfQ",
"CertificateOptions:Password": "secret"
}
假设 API 包装 returns 此数据包装为:
{
"Application": "MyApp",
"LastChanged": "2021-08-09 14:38:00",
"Data": {
"CertificateOptions:PfxBase64": "MIIK...oCAgfQ",
"CertificateOptions:Password": "secret"
}
}
所以我们在获取数据时只需要考虑 Data
键。
class RemoteConfigurationSource : IConfigurationSource
{
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new RemoteConfigurationProvider();
}
private class RemoteConfigurationProvider : ConfigurationProvider
{
public override void Load()
{
// We cannot await this method, so have to do sync-over-async.
// Not an issue, because it's a one-time thing.
var result = LoadRemoteConfig().GetAwaiter().GetResult();
Data = result.Data;
}
private async Task<RemoteConfigResult> LoadRemoteConfig()
{
// We cannot use IHttpClientFactory here, since ServiceProvider isn't even built yet.
using var httpClient = new HttpClient();
// ... add headers, token to request
return await httpClient.GetFromJsonAsync<RemoteConfigResult>("https://example.com/path/to/json");
}
}
private class RemoteConfigResult
{
public Dictionary<string, string> Data { get; set; }
}
}
为了稍微清理一下,我们可以将 URL 和其他凭据移动到 appsettings.json:
{
"Logging": {
/*...*/
},
"RemoteConfiguration": {
"Url": "https://jsonkeeper.com/b/B78I",
"ApplicationId": "myconfigappid",
"Secret": "myconfigapisecret"
}
}
然后构建一个临时的 IConfiguration
根据需要添加尽可能多的源,然后获取这些值:
// Read credentials from appsettings.json
var remoteConfigurationOptions = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false)
.Build()
.GetSection(RemoteConfigurationOptions.ConfigurationKey)
.Get<RemoteConfigurationOptions>();
public class RemoteConfigurationOptions
{
public const string ConfigurationKey = "RemoteConfiguration";
public string Url { get; set; }
public string ApplicationId { get; set; }
public string Secret { get; set; }
}
然后将这个对象传递给我们的配置源,配置源又将它传递给配置提供者
这感觉像是一个简单的问题,但在我所有的搜索中,我仍然没有找到适合我的解决方案。可能是另一种找不到我想要的东西的情况,因为我没有搜索正确的 'thing',但我们在这里..
我有一个 C# Web API 程序,我想在其中从配置对象配置 kestrel 服务器。
我通过 rest 调用将此配置接收到我的服务中,进入 CustomConfig
对象。我可以在 Program.cs
或 Startup.cs
中获取此配置对象,但由于我不想重复自己并进行额外的调用,所以我不想在这两个地方都这样做。
我的偏好是在 Startup.cs
中获取配置,因为这是我的其余配置代码所在的位置,也是我已经在使用我的 CustomConfig
对象的位置。但是,我找不到一种方法来配置 kestrel 服务器以使用我给它的证书(在 Startup.cs 中),我也看不到将此配置从 Startup.cs
注入 Startup.cs
的方法=13=].
在其他项目中,我将 PFX 文件的位置作为环境变量传递:ASPNETCORE_Kestrel__Certificates__Default__Path
(在这种情况下,无需额外的代码配置,一切正常),但在这个项目中,所有配置都必须通过 rest 检索打电话,所以这不是这里的一个选项。
我目前拥有所有东西 运行,但只能通过调用 rest 两次来获取配置。当前配置 kestrel 的实现是将 PFX 存储在 CustomConfig
中作为 base64 字符串,并在 Program.cs
:
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
CustomConfig config = CustomConfig() // <- I receive config here
webBuilder.UseStartup<Startup>();
webBuilder.UseKestrel(options =>
{
options.ConfigureHttpsDefaults(d =>
{
byte[] pfxBytes = Convert.FromBase64String(config.Base64PFXBytes);
d.ServerCertificate = new X509Certificate2(pfxBytes, "sslKey");
});
});
});
}
总结一下..
- 我有一个
CustomConfig
对象,用于在Startup.cs
中配置服务
- 我想从
CustomConfig
配置我的 Kestrel 服务器
所以我正在寻求帮助:
- 让 Kestrel 在
Startup.cs
内使用我的 PFX
- 将
CustomConfig
对象从Program.cs
传递到Startup.cs
希望这是有道理的。为了清楚起见,欢迎提出任何和所有解决方案/其他问题!
提前致谢!
ASP.NET 核心使用 IConfiguration
接口抽象配置。不细说,收集
来自各种 IConfigurationSource
的配置并将它们叠加在一起,这让我们可以覆盖
通过使用相同的键定义在另一个源中定义的设置。
1。实施 IConfigurationSource
让我们实施一个 IConfigurationSource
。我们可以使用 ConfigurationSource
摘要 class 作为我们的起点。出色地
使用内存中实现,然后切换到远程源。
class RemoteConfigurationSource : IConfigurationSource
{
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new RemoteConfigurationProvider(_options);
}
private class RemoteConfigurationProvider : ConfigurationProvider
{
public override void Load()
{
// TODO: fetch data from the API
var remoteConfig = new Dictionary<string, string>
{
{ "CertificateOptions:PfxBase64", "MIIKkQIBAz....gfQ" },
{ "CertificateOptions:Password", "secret" },
};
Data = remoteConfig;
}
}
}
然后将其添加到 ConfigureHostConfiguration
回调中的配置生成器:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureHostConfiguration(builder =>
{
// add new source
builder.AddRemoteConfiguration();
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>().UseKestrel((context, options) =>
{
var certificateOptions = context.Configuration
.GetSection(KestrelCertificateOptions.ConfigurationKey)
.Get<KestrelCertificateOptions>();
options.ConfigureHttpsDefaults(adapterOptions =>
adapterOptions.ServerCertificate = certificateOptions.Certificate);
});
});
}
public static class ConfigurationBuilderExtensions
{
public static IConfigurationBuilder AddRemoteConfiguration(this IConfigurationBuilder builder) =>
builder.Add(new RemoteConfigurationSource());
}
class KestrelCertificateOptions
{
public const string ConfigurationKey = "CertificateOptions";
public string PfxBase64 { get; set; }
public string Password { get; set; }
public X509Certificate2 Certificate => new X509Certificate2(Convert.FromBase64String(PfxBase64), Password);
}
当我们 运行 应用程序时,ASP.NET 核心将加载并使用我们的内存配置。
2。从 API
获取配置数据现在让我们从远程 API 获取配置。它需要 return 配置值,部分名称以分隔
带有冒号 :
。这是与 JSON 相同的配置,在 CertificateOptions
部分下归档:
{
"CertificateOptions:PfxBase64": "MII....oCAgfQ",
"CertificateOptions:Password": "secret"
}
假设 API 包装 returns 此数据包装为:
{
"Application": "MyApp",
"LastChanged": "2021-08-09 14:38:00",
"Data": {
"CertificateOptions:PfxBase64": "MIIK...oCAgfQ",
"CertificateOptions:Password": "secret"
}
}
所以我们在获取数据时只需要考虑 Data
键。
class RemoteConfigurationSource : IConfigurationSource
{
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new RemoteConfigurationProvider();
}
private class RemoteConfigurationProvider : ConfigurationProvider
{
public override void Load()
{
// We cannot await this method, so have to do sync-over-async.
// Not an issue, because it's a one-time thing.
var result = LoadRemoteConfig().GetAwaiter().GetResult();
Data = result.Data;
}
private async Task<RemoteConfigResult> LoadRemoteConfig()
{
// We cannot use IHttpClientFactory here, since ServiceProvider isn't even built yet.
using var httpClient = new HttpClient();
// ... add headers, token to request
return await httpClient.GetFromJsonAsync<RemoteConfigResult>("https://example.com/path/to/json");
}
}
private class RemoteConfigResult
{
public Dictionary<string, string> Data { get; set; }
}
}
为了稍微清理一下,我们可以将 URL 和其他凭据移动到 appsettings.json:
{
"Logging": {
/*...*/
},
"RemoteConfiguration": {
"Url": "https://jsonkeeper.com/b/B78I",
"ApplicationId": "myconfigappid",
"Secret": "myconfigapisecret"
}
}
然后构建一个临时的 IConfiguration
根据需要添加尽可能多的源,然后获取这些值:
// Read credentials from appsettings.json
var remoteConfigurationOptions = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false)
.Build()
.GetSection(RemoteConfigurationOptions.ConfigurationKey)
.Get<RemoteConfigurationOptions>();
public class RemoteConfigurationOptions
{
public const string ConfigurationKey = "RemoteConfiguration";
public string Url { get; set; }
public string ApplicationId { get; set; }
public string Secret { get; set; }
}
然后将这个对象传递给我们的配置源,配置源又将它传递给配置提供者