如何从模块配置服务访问 appsettings.json



我有一个包含appsettings.json的blazer服务器端解决方案。

我正在应用程序项目的应用程序模块中的配置服务替代中配置 blob 存储。 它当前具有硬编码的连接字符串,并且工作正常。

现在,我想将连接字符串移动到 Blazor 项目中的 appsettings.json 文件。

我试图将 IConfiguration 注入到应用程序模块的构造函数中,但是当我尝试这样做时,应用程序会抛出错误。

我已经搜索了传递给ConfigureServices覆盖的ServiceConfigurationContext。 有一个 Service 属性包含大约 1,024 个 ServiceScriptor 的集合,并在 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;
});
});
});
}
}
}

此答案已根据问题中的新信息进行了更新。

如果我正确理解上下文,您正在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": "*"
}

接下来定义一个数据类来保存配置数据

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"));

最后是组件。

注意:

  1. 我们使用IOptions<AzureData>来获取特定的配置实例,Value来获取实际对象。
  2. 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"
}

就是这样!

谢谢乔花时间回答我的问题!

对于可能正在寻找同一问题解决方案的其他人 - 我有几件事要补充。我使用的是具有单独Product.IdentityServerProduct.WebProduct.HttpApi.Host项目的分离租户。

我尝试执行的配置是针对AbpTwilioSmsModuleAbpBlobStoringModule。这些模块的值被硬编码到我的Product.Domain.ProductDomainModule类。

// 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:ProductDevFiles"; });
});
});

我修改了该代码以尝试从上下文中读取,就像 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"];
});
});
});

在这一点上,我遇到了这篇文章,并找到了如何从上下文中获取配置对象。

然而,并非一切都很好...

很长一段时间我都无法理解为什么我无法读取放置在Product.HttpApi.Host根文件夹中的appsettings.json配置信息。我能够访问配置对象,但我的值仍然null

然后我想到我应该将一个appsettings.json文件添加到我的Product.Domain根文件夹中;令人惊讶的是,这没有任何效果。

我终于开始将服务配置代码从我的Product.Domain.ProductDomainModule类移到我的Product.HttpApi.Host.ProductHttpApiHostModule类和Product.IdentityServer.ProductIdentityServerModule类中。

[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.Hostappsettings.json文件复制到我的Product.IdentityServerappsettings.json文件中,一切都运行良好。

{
...,
"AbpTwilioSms": {
"AccountSId": "yada-yada-yada",
"AuthToken": "yada-yada-yada",
"FromNumber": "+18885551212"
},
"AbpBlobStoring": {
"IsMultiTenant": true,
"FileSystemBasePath": "D:\Product\DevFiles\"
}
}

最新更新