【问题标题】:How to access appsettings.json from module Configure Services如何从模块配置服务访问 appsettings.json
【发布时间】:2022-01-21 18:22:38
【问题描述】:

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

我正在应用程序项目的应用程序模块的 ConfigureServices 覆盖中配置 blob 存储。它目前有一个硬编码的连接字符串,并且运行良好。

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

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

我搜索了传递给 ConfigureServices 覆盖的 ServiceConfigurationContext。有一个 Service 属性包含大约 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;
                });
              });
            });
        }
    }
}

【问题讨论】:

    标签: module blazor azure-blob-storage connection-string appsettings


    【解决方案1】:

    通过查看解决方案中的其他模块,我终于找到了问题的答案。

    这是更新后的代码

    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"
    }
    

    就是这样!

    感谢乔投入时间为我的问题提供答案!

    【讨论】:

      【解决方案2】:

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

      如果我正确理解上下文,您正在MyAppApplicationModule 中构建自己的 DI 服务容器。由于我没有关于MyAppApplicationModule 的足够详细信息,我将演示如何在OwningComponentBase 的上下文中获取应用程序配置数据,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&lt;AzureData&gt;获取具体配置实例,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();
          }
      }
      

      【讨论】:

      • 我已经更新了我上面的帖子,以包含我试图从中访问 appsettings.json 的模块。依赖注入无法将 IConfiguration 传递给构造函数,我不知道如何从传递给 ConfigureServices 覆盖的 ServiceConfigurationContext 中获取 IConfiguration。有什么想法吗?
      • @Joe - 我已经更新了我的答案。我猜对了MyAppApplicationModule 的上下文吗?
      • 我为不够清楚而道歉。我的目标是将连接字符串从 appsettings.json 传递到上面的模块中,因此我不需要在“azure.ConnectionString =”DefaultEndpointsProtocol=https;AccountName=MyApplocalsa;AccountKey=;EndpointSuffix=core.windows.net";"。我正在努力了解如何将 appsettings.json 中的任何值添加到模块中。将 IConfiguration 注入构造函数失败,我不知道如何从传递给 ConfigureServices 的 ServiceConfigurationContext 中获取它。
      • 感谢您抽出宝贵时间更新您的上述答案! @MrC 又名肖恩·柯蒂斯
      【解决方案3】:

      对于可能正在寻找解决同一问题的其他人 - 我有几件事要补充。我正在使用一个单独的租户和单独的 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:\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"];
                  });
                });
              });
      

      那时我看到了这篇文章,发现了如何将配置对象从上下文中取出。

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

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

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

      我终于开始将服务配置代码从我的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.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\\"
            }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多