如何从配置服务模块访问 appsettings.json
How to access appsettings.json from module Configure Services
我有一个包含 appsettings.json
的 Blazor 服务器端解决方案
我正在应用程序项目的应用程序模块中的 ConfigureServices 覆盖中配置 blob 存储。它目前有一个硬编码的连接字符串,并且运行良好。
现在我想将连接字符串移动到 Blazor 项目中的 appsettings.json 文件。
我尝试将 IConfiguration 注入到 ApplicationModule 的构造函数中,但是当我尝试这样做时应用程序抛出错误。
我搜索了传递给 ConfigureServices 覆盖的 ServiceConfigurationContext。有一项服务 属性 包含大约 1,024 个 ServiceDescriptors 的集合,并在 ServiceType.FullName 中找到了一个包含单词 IConfiguration 的服务,但一直无法弄清楚如何使用它来获取服务本身为了获得 appsettings.json 值。
任何人都可以阐明如何从应用程序模块访问 appsettings.json 值吗?
这是我正在使用的代码
namespace MyApp
{
[DependsOn(
typeof(MyAppDomainModule),
typeof(AbpAccountApplicationModule),
typeof(MyAppApplicationContractsModule),
typeof(AbpIdentityApplicationModule),
typeof(AbpPermissionManagementApplicationModule),
typeof(AbpTenantManagementApplicationModule),
typeof(AbpFeatureManagementApplicationModule),
typeof(AbpSettingManagementApplicationModule),
typeof(AbpBlobStoringModule),
typeof(AbpBlobStoringAzureModule)
)]
public class MyAppApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpBlobStoringOptions>(options =>
{
options.Containers.ConfigureDefault(container =>
{
container.UseAzure(azure =>
{
azure.ConnectionString = "DefaultEndpointsProtocol=https;AccountName=MyApplocalsa;AccountKey=<truncated-account-key>;EndpointSuffix=core.windows.net";
azure.ContainerName = "Pictures";
azure.CreateContainerIfNotExists = true;
});
});
});
}
}
}
This answer has been update based on new information in the question.
如果我对上下文的理解正确,那么您正在 MyAppApplicationModule
中构建您自己的 DI 服务容器。由于我没有关于 MyAppApplicationModule
的足够详细信息,我将演示如何在 OwningComponentBase
的上下文中获取应用程序配置数据,它还定义了它自己的 DI 服务容器。注意我这里用的是Net6.0
首先是web项目appsettings.json中的配置数据
{
"AzureData": {
"ConnectionString": "DefaultEndpointsProtocol=https;AccountName=MyApplocalsa;AccountKey=<truncated-account-key>;EndpointSuffix=core.windows.net",
"ContainerName": "Pictures"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
接下来定义一个数据class来保存配置数据
public class AzureData
{
public readonly Guid Id = Guid.NewGuid();
public string ConnectionString { get; set; } = string.Empty;
public string ContainerName { get; set; } = string.Empty;
}
现在注册一个配置实例,将 AzureData
实例绑定到配置文件中的一个部分。
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
builder.Services.Configure<AzureData>(builder.Configuration.GetSection("AzureData"));
最后是组件。
注:
- 我们使用
IOptions<AzureData>
获取具体配置实例,Value
获取实际对象
AzureData
是同一个 DI 对象,在本地服务容器内部或外部。它被定义为单例。
@page "/di"
@inherits OwningComponentBase
@using Microsoft.Extensions.Options
<h3>DI Component</h3>
<div class="m-2 p-2">
Main Service Container <br />
Id: @AzureDataConfig?.Value.Id <br />
Connection String: @AzureDataConfig?.Value.ConnectionString
</div>
<div class="m-2 p-2">
Component Service Container <br />
Id:@azureData?.Value.Id <br />
Connection String: @azureData?.Value.ConnectionString
</div>
@code {
[Inject] private IOptions<AzureData>? AzureDataConfig { get; set; }
private IOptions<AzureData>? azureData;
protected override void OnInitialized()
{
azureData = ScopedServices.GetService<IOptions<AzureData>>();
base.OnInitialized();
}
}
通过查看解决方案中的其他模块,我终于找到了问题的答案。
这是更新后的代码
namespace MyApp
{
[DependsOn(
typeof(MyAppDomainModule),
typeof(AbpAccountApplicationModule),
typeof(MyAppApplicationContractsModule),
typeof(AbpIdentityApplicationModule),
typeof(AbpPermissionManagementApplicationModule),
typeof(AbpTenantManagementApplicationModule),
typeof(AbpFeatureManagementApplicationModule),
typeof(AbpSettingManagementApplicationModule),
typeof(AbpBlobStoringModule),
typeof(AbpBlobStoringAzureModule)
)]
public class MyAppApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddMaps<MyAppApplicationModule>();
});
Configure<AbpBlobStoringOptions>(options =>
{
options.Containers.ConfigureDefault(container =>
{
container.UseAzure(azure =>
{
azure.ConnectionString = configuration.GetSection("BlobStorage:ConnectionString").Value;
azure.ContainerName = configuration.GetSection("BlobStorage:ContainerName").Value;
azure.CreateContainerIfNotExists = true;
});
});
});
}
}
}
我需要添加使用
using Microsoft.Extensions.DependencyInjection;
我能够获得对配置的引用
var configuration = context.Services.GetConfiguration();
我更新了硬编码的连接字符串,从配置中检索它。
azure.ConnectionString = configuration.GetSection("BlobStorage:ConnectionString").Value;
azure.ContainerName = configuration.GetSection("BlobStorage:ContainerName").Value;
我更新了 Blazor 应用程序中的 appsettings.json 文件
"BlobStorage": {
"ConnectionString": "DefaultEndpointsProtocol=https;AccountName=myapplocalsa;AccountKey=<truncated>;EndpointSuffix=core.windows.net",
"ContainerName" : "Pictures"
}
就是这样!
感谢 Joe 花时间回答我的问题!
对于可能正在寻找同一问题的解决方案的其他人 - 我有几件事要补充。我正在使用一个单独的租户,其中包含单独的 Product.IdentityServer
、Product.Web
和 Product.HttpApi.Host
项目。
我尝试执行的配置是针对 AbpTwilioSmsModule
和 AbpBlobStoringModule
。这些模块的值被硬编码到我的
Product.Domain.ProductDomainModule
class.
// TODO - Need to configure this through appsettings.json - JLavallet 2022-02-10 12:23
Configure<AbpTwilioSmsOptions>(options =>
{
options.AccountSId = "yada-yada-yada";
options.AuthToken = "yada-yada-yada";
options.FromNumber = "+18885551212";
});
// TODO - Need to configure this through appsettings.json - JLavallet 2022-02-10 12:24
Configure<AbpBlobStoringOptions>(options =>
{
options.Containers.ConfigureDefault(container =>
{
container.IsMultiTenant = true;
container.UseFileSystem(fileSystem => { fileSystem.BasePath = @"D:\Product\DevFiles"; });
});
});
我修改了该代码以尝试像 OP 一样从上下文中读取。我不确定上下文的 属性 包含配置。我尝试了各种方法并设置断点来尝试在上下文中找到配置对象,但没有成功。
Configure<AbpTwilioSmsOptions>(options =>
{
options.AccountSId = context.WHAT?["AbpTwilioSms:AccountSId"];
options.AuthToken = context.WHAT?["AbpTwilioSms:AuthToken"];
options.FromNumber = context.WHAT?["AbpTwilioSms:FromNumber"];
});
Configure<AbpBlobStoringOptions>(options =>
{
options.Containers.ConfigureDefault(container =>
{
container.IsMultiTenant = Convert.ToBoolean(context.WHAT?["AbpBlobStoring:IsMultiTenant"]);
container.UseFileSystem(fileSystem =>
{
fileSystem.BasePath = context.WHAT?["AbpBlobStoring:FileSystemBasePath"];
});
});
});
那时我遇到了这个 post 并找到了如何从上下文中获取配置对象。
并非一切都很好,但是……
很长一段时间我都不明白为什么我无法读取我放在 Product.HttpApi.Host
根文件夹中的 appsettings.json
配置信息。我能够访问配置对象,但我的值仍然是 null
.
然后我想到我应该在我的 Product.Domain
根文件夹中添加一个 appsettings.json
文件;令人惊讶的是没有效果。
我终于开始将服务配置代码从我的 Product.Domain.ProductDomainModule
class 移到我的 Product.HttpApi.Host.ProductHttpApiHostModule
class 和我的 Product.IdentityServer.ProductIdentityServerModule
class.
[DependsOn(
typeof(ProductHttpApiModule),
typeof(AbpAutofacModule),
typeof(AbpCachingStackExchangeRedisModule),
typeof(AbpAspNetCoreMvcUiMultiTenancyModule),
typeof(AbpIdentityAspNetCoreModule),
typeof(ProductApplicationModule),
typeof(ProductEntityFrameworkCoreModule),
typeof(AbpSwashbuckleModule),
typeof(AbpAspNetCoreSerilogModule)
)]
// added by Jack
[DependsOn(typeof(AbpTwilioSmsModule))]
[DependsOn(typeof(AbpBlobStoringModule))]
[DependsOn(typeof(AbpBlobStoringFileSystemModule))]
public class ProductHttpApiHostModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
var hostingEnvironment = context.Services.GetHostingEnvironment();
ConfigureUrls(configuration);
ConfigureConventionalControllers();
ConfigureAuthentication(context, configuration);
ConfigureSwagger(context, configuration);
ConfigureCache(configuration);
ConfigureVirtualFileSystem(context);
ConfigureDataProtection(context, configuration, hostingEnvironment);
ConfigureCors(context, configuration);
ConfigureExternalProviders(context);
ConfigureHealthChecks(context);
ConfigureTenantResolver(context, configuration);
//added by Jack
ConfigureTwilioSms(configuration);
ConfigureBlobStoring(configuration);
}
private void ConfigureBlobStoring(IConfiguration configuration)
{
Configure<AbpBlobStoringOptions>(options =>
{
options.Containers.ConfigureDefault(container =>
{
container.IsMultiTenant = Convert.ToBoolean(configuration["AbpBlobStoring:IsMultiTenant"]);
container.UseFileSystem(fileSystem =>
{
fileSystem.BasePath = configuration["AbpBlobStoring:FileSystemBasePath"];
});
});
});
}
private void ConfigureTwilioSms(IConfiguration configuration)
{
Configure<AbpTwilioSmsOptions>(options =>
{
options.AccountSId = configuration["AbpTwilioSms:AccountSId"];
options.AuthToken = configuration["AbpTwilioSms:AuthToken"];
options.FromNumber = configuration["AbpTwilioSms:FromNumber"];
});
}
然后我将我的配置条目从 Product.HttpApi.Host\appsettings.json
文件复制到我的 Product.IdentityServer\appsettings.json
文件中,一切都很顺利。
{
...,
"AbpTwilioSms": {
"AccountSId": "yada-yada-yada",
"AuthToken": "yada-yada-yada",
"FromNumber": "+18885551212"
},
"AbpBlobStoring": {
"IsMultiTenant": true,
"FileSystemBasePath": "D:\Product\DevFiles\"
}
}
我有一个包含 appsettings.json
的 Blazor 服务器端解决方案我正在应用程序项目的应用程序模块中的 ConfigureServices 覆盖中配置 blob 存储。它目前有一个硬编码的连接字符串,并且运行良好。
现在我想将连接字符串移动到 Blazor 项目中的 appsettings.json 文件。
我尝试将 IConfiguration 注入到 ApplicationModule 的构造函数中,但是当我尝试这样做时应用程序抛出错误。
我搜索了传递给 ConfigureServices 覆盖的 ServiceConfigurationContext。有一项服务 属性 包含大约 1,024 个 ServiceDescriptors 的集合,并在 ServiceType.FullName 中找到了一个包含单词 IConfiguration 的服务,但一直无法弄清楚如何使用它来获取服务本身为了获得 appsettings.json 值。
任何人都可以阐明如何从应用程序模块访问 appsettings.json 值吗?
这是我正在使用的代码
namespace MyApp
{
[DependsOn(
typeof(MyAppDomainModule),
typeof(AbpAccountApplicationModule),
typeof(MyAppApplicationContractsModule),
typeof(AbpIdentityApplicationModule),
typeof(AbpPermissionManagementApplicationModule),
typeof(AbpTenantManagementApplicationModule),
typeof(AbpFeatureManagementApplicationModule),
typeof(AbpSettingManagementApplicationModule),
typeof(AbpBlobStoringModule),
typeof(AbpBlobStoringAzureModule)
)]
public class MyAppApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpBlobStoringOptions>(options =>
{
options.Containers.ConfigureDefault(container =>
{
container.UseAzure(azure =>
{
azure.ConnectionString = "DefaultEndpointsProtocol=https;AccountName=MyApplocalsa;AccountKey=<truncated-account-key>;EndpointSuffix=core.windows.net";
azure.ContainerName = "Pictures";
azure.CreateContainerIfNotExists = true;
});
});
});
}
}
}
This answer has been update based on new information in the question.
如果我对上下文的理解正确,那么您正在 MyAppApplicationModule
中构建您自己的 DI 服务容器。由于我没有关于 MyAppApplicationModule
的足够详细信息,我将演示如何在 OwningComponentBase
的上下文中获取应用程序配置数据,它还定义了它自己的 DI 服务容器。注意我这里用的是Net6.0
首先是web项目appsettings.json中的配置数据
{
"AzureData": {
"ConnectionString": "DefaultEndpointsProtocol=https;AccountName=MyApplocalsa;AccountKey=<truncated-account-key>;EndpointSuffix=core.windows.net",
"ContainerName": "Pictures"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
接下来定义一个数据class来保存配置数据
public class AzureData
{
public readonly Guid Id = Guid.NewGuid();
public string ConnectionString { get; set; } = string.Empty;
public string ContainerName { get; set; } = string.Empty;
}
现在注册一个配置实例,将 AzureData
实例绑定到配置文件中的一个部分。
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
builder.Services.Configure<AzureData>(builder.Configuration.GetSection("AzureData"));
最后是组件。
注:
- 我们使用
IOptions<AzureData>
获取具体配置实例,Value
获取实际对象 AzureData
是同一个 DI 对象,在本地服务容器内部或外部。它被定义为单例。
@page "/di"
@inherits OwningComponentBase
@using Microsoft.Extensions.Options
<h3>DI Component</h3>
<div class="m-2 p-2">
Main Service Container <br />
Id: @AzureDataConfig?.Value.Id <br />
Connection String: @AzureDataConfig?.Value.ConnectionString
</div>
<div class="m-2 p-2">
Component Service Container <br />
Id:@azureData?.Value.Id <br />
Connection String: @azureData?.Value.ConnectionString
</div>
@code {
[Inject] private IOptions<AzureData>? AzureDataConfig { get; set; }
private IOptions<AzureData>? azureData;
protected override void OnInitialized()
{
azureData = ScopedServices.GetService<IOptions<AzureData>>();
base.OnInitialized();
}
}
通过查看解决方案中的其他模块,我终于找到了问题的答案。
这是更新后的代码
namespace MyApp
{
[DependsOn(
typeof(MyAppDomainModule),
typeof(AbpAccountApplicationModule),
typeof(MyAppApplicationContractsModule),
typeof(AbpIdentityApplicationModule),
typeof(AbpPermissionManagementApplicationModule),
typeof(AbpTenantManagementApplicationModule),
typeof(AbpFeatureManagementApplicationModule),
typeof(AbpSettingManagementApplicationModule),
typeof(AbpBlobStoringModule),
typeof(AbpBlobStoringAzureModule)
)]
public class MyAppApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddMaps<MyAppApplicationModule>();
});
Configure<AbpBlobStoringOptions>(options =>
{
options.Containers.ConfigureDefault(container =>
{
container.UseAzure(azure =>
{
azure.ConnectionString = configuration.GetSection("BlobStorage:ConnectionString").Value;
azure.ContainerName = configuration.GetSection("BlobStorage:ContainerName").Value;
azure.CreateContainerIfNotExists = true;
});
});
});
}
}
}
我需要添加使用
using Microsoft.Extensions.DependencyInjection;
我能够获得对配置的引用
var configuration = context.Services.GetConfiguration();
我更新了硬编码的连接字符串,从配置中检索它。
azure.ConnectionString = configuration.GetSection("BlobStorage:ConnectionString").Value;
azure.ContainerName = configuration.GetSection("BlobStorage:ContainerName").Value;
我更新了 Blazor 应用程序中的 appsettings.json 文件
"BlobStorage": {
"ConnectionString": "DefaultEndpointsProtocol=https;AccountName=myapplocalsa;AccountKey=<truncated>;EndpointSuffix=core.windows.net",
"ContainerName" : "Pictures"
}
就是这样!
感谢 Joe 花时间回答我的问题!
对于可能正在寻找同一问题的解决方案的其他人 - 我有几件事要补充。我正在使用一个单独的租户,其中包含单独的 Product.IdentityServer
、Product.Web
和 Product.HttpApi.Host
项目。
我尝试执行的配置是针对 AbpTwilioSmsModule
和 AbpBlobStoringModule
。这些模块的值被硬编码到我的
Product.Domain.ProductDomainModule
class.
// TODO - Need to configure this through appsettings.json - JLavallet 2022-02-10 12:23
Configure<AbpTwilioSmsOptions>(options =>
{
options.AccountSId = "yada-yada-yada";
options.AuthToken = "yada-yada-yada";
options.FromNumber = "+18885551212";
});
// TODO - Need to configure this through appsettings.json - JLavallet 2022-02-10 12:24
Configure<AbpBlobStoringOptions>(options =>
{
options.Containers.ConfigureDefault(container =>
{
container.IsMultiTenant = true;
container.UseFileSystem(fileSystem => { fileSystem.BasePath = @"D:\Product\DevFiles"; });
});
});
我修改了该代码以尝试像 OP 一样从上下文中读取。我不确定上下文的 属性 包含配置。我尝试了各种方法并设置断点来尝试在上下文中找到配置对象,但没有成功。
Configure<AbpTwilioSmsOptions>(options =>
{
options.AccountSId = context.WHAT?["AbpTwilioSms:AccountSId"];
options.AuthToken = context.WHAT?["AbpTwilioSms:AuthToken"];
options.FromNumber = context.WHAT?["AbpTwilioSms:FromNumber"];
});
Configure<AbpBlobStoringOptions>(options =>
{
options.Containers.ConfigureDefault(container =>
{
container.IsMultiTenant = Convert.ToBoolean(context.WHAT?["AbpBlobStoring:IsMultiTenant"]);
container.UseFileSystem(fileSystem =>
{
fileSystem.BasePath = context.WHAT?["AbpBlobStoring:FileSystemBasePath"];
});
});
});
那时我遇到了这个 post 并找到了如何从上下文中获取配置对象。
并非一切都很好,但是……
很长一段时间我都不明白为什么我无法读取我放在 Product.HttpApi.Host
根文件夹中的 appsettings.json
配置信息。我能够访问配置对象,但我的值仍然是 null
.
然后我想到我应该在我的 Product.Domain
根文件夹中添加一个 appsettings.json
文件;令人惊讶的是没有效果。
我终于开始将服务配置代码从我的 Product.Domain.ProductDomainModule
class 移到我的 Product.HttpApi.Host.ProductHttpApiHostModule
class 和我的 Product.IdentityServer.ProductIdentityServerModule
class.
[DependsOn(
typeof(ProductHttpApiModule),
typeof(AbpAutofacModule),
typeof(AbpCachingStackExchangeRedisModule),
typeof(AbpAspNetCoreMvcUiMultiTenancyModule),
typeof(AbpIdentityAspNetCoreModule),
typeof(ProductApplicationModule),
typeof(ProductEntityFrameworkCoreModule),
typeof(AbpSwashbuckleModule),
typeof(AbpAspNetCoreSerilogModule)
)]
// added by Jack
[DependsOn(typeof(AbpTwilioSmsModule))]
[DependsOn(typeof(AbpBlobStoringModule))]
[DependsOn(typeof(AbpBlobStoringFileSystemModule))]
public class ProductHttpApiHostModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
var hostingEnvironment = context.Services.GetHostingEnvironment();
ConfigureUrls(configuration);
ConfigureConventionalControllers();
ConfigureAuthentication(context, configuration);
ConfigureSwagger(context, configuration);
ConfigureCache(configuration);
ConfigureVirtualFileSystem(context);
ConfigureDataProtection(context, configuration, hostingEnvironment);
ConfigureCors(context, configuration);
ConfigureExternalProviders(context);
ConfigureHealthChecks(context);
ConfigureTenantResolver(context, configuration);
//added by Jack
ConfigureTwilioSms(configuration);
ConfigureBlobStoring(configuration);
}
private void ConfigureBlobStoring(IConfiguration configuration)
{
Configure<AbpBlobStoringOptions>(options =>
{
options.Containers.ConfigureDefault(container =>
{
container.IsMultiTenant = Convert.ToBoolean(configuration["AbpBlobStoring:IsMultiTenant"]);
container.UseFileSystem(fileSystem =>
{
fileSystem.BasePath = configuration["AbpBlobStoring:FileSystemBasePath"];
});
});
});
}
private void ConfigureTwilioSms(IConfiguration configuration)
{
Configure<AbpTwilioSmsOptions>(options =>
{
options.AccountSId = configuration["AbpTwilioSms:AccountSId"];
options.AuthToken = configuration["AbpTwilioSms:AuthToken"];
options.FromNumber = configuration["AbpTwilioSms:FromNumber"];
});
}
然后我将我的配置条目从 Product.HttpApi.Host\appsettings.json
文件复制到我的 Product.IdentityServer\appsettings.json
文件中,一切都很顺利。
{
...,
"AbpTwilioSms": {
"AccountSId": "yada-yada-yada",
"AuthToken": "yada-yada-yada",
"FromNumber": "+18885551212"
},
"AbpBlobStoring": {
"IsMultiTenant": true,
"FileSystemBasePath": "D:\Product\DevFiles\"
}
}