首页 > 解决方案 > 在无状态 asp.net 核心服务结构应用程序中读取 appsettings.json

问题描述

我创建了一个 asp.net core 2.1 API 项目(不在服务结构内),如果我将此代码添加到 ValuesController.cs 我可以从 appsettings.json 检索配置

    private IConfiguration configuration;

    public ValuesController(IConfiguration iConfig)
    {
        configuration = iConfig;
    }
    // GET api/values
    [HttpGet]
    public ActionResult<IEnumerable<string>> Get()
    {
        string dbConn = configuration.GetSection("MySettings").GetSection("DbConnection").Value;
        return new string[] { "value1", "value2" };
    }

我创建了一个无状态的 asp.net Core API Service Fabric 项目的同一个类似项目,默认情况下这不起作用我必须添加对 appsetting.json 的特定引用。当我看这个项目时,它们看起来都非常相似。这是正确的方法吗?在非服务结构项目中不需要这样。

return new WebHostBuilder()
                                    .UseKestrel()
                                    .ConfigureAppConfiguration((builderContext, config) =>
                                        {
                                            config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
                                        })
                                    .ConfigureServices(
                                        services => services
                                            .AddSingleton<StatelessServiceContext>(serviceContext))
                                    .UseContentRoot(Directory.GetCurrentDirectory())
                                    .UseStartup<Startup>()
                                    .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                                    .UseUrls(url)
                                    .Build();

标签: asp.net-core-webapiazure-service-fabricasp.net-core-2.1

解决方案


在 Service Fabric 内部,我根本不使用应用程序设置。我遵循的方法是将所有服务的每个设置都保存在一个位置,即 Service Fabric 项目中的 ApplicationPackageRoot/ApplicationManifest.xml。例如,如果我有两个服务,ApplicationManifest 可能如下所示:

<?xml version="1.0" encoding="utf-8"?>
<ApplicationManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ApplicationTypeName="TestAppType" 
ApplicationTypeVersion="1.0.0" xmlns="http://schemas.microsoft.com/2011/01/fabric">
  <Parameters>
    <Parameter Name="Environment" DefaultValue="" />
    <Parameter Name="TestWebApi_InstanceCount" DefaultValue="" />
    <Parameter Name="TestServiceName" DefaultValue="TestService" />
    <Parameter Name="TestService_InstanceCount" DefaultValue="" />
  </Parameters>
  <ServiceManifestImport>
    <ServiceManifestRef ServiceManifestName="TestServicePkg" ServiceManifestVersion="1.0.0" />
    <ConfigOverrides>
      <ConfigOverride Name="Config">
        <Settings>
          <Section Name="General">
            <Parameter Name="Environment" Value="[Environment]" />
            <Parameter Name="TestServiceName" Value="[TestServiceName]" />
          </Section>
        </Settings>
      </ConfigOverride>
    </ConfigOverrides>
  </ServiceManifestImport>
  <ServiceManifestImport>
    <ServiceManifestRef ServiceManifestName="TestWebApiPkg" ServiceManifestVersion="1.0.0" />
    <ConfigOverrides>
      <ConfigOverride Name="Config">
        <Settings>
          <Section Name="General">
            <Parameter Name="Environment" Value="[Environment]" />
          </Section>
        </Settings>
      </ConfigOverride>
    </ConfigOverrides>
  </ServiceManifestImport>
  <DefaultServices>
    <Service Name="TestService" ServicePackageActivationMode="ExclusiveProcess">
      <StatelessService ServiceTypeName="TestServiceType" InstanceCount="[TestService_InstanceCount]">
        <SingletonPartition />
      </StatelessService>
    </Service>
    <Service Name="TestWebApi" ServicePackageActivationMode="ExclusiveProcess">
      <StatelessService ServiceTypeName="TestWebApiType" InstanceCount="[TestWebApi_InstanceCount]">
        <SingletonPartition />
      </StatelessService>
    </Service>
  </DefaultServices>
</ApplicationManifest>

我只是把用于应用程序的参数的定义和每个服务的特定配置放在那里。下一步是为您放置实际值的每个环境准备应用程序参数文件,例如 Dev.xml:

<?xml version="1.0" encoding="utf-8"?>
<Application xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Name="fabric:/TestApp" xmlns="http://schemas.microsoft.com/2011/01/fabric">
  <Parameters>
    <Parameter Name="Environment" Value="Dev" />
    <Parameter Name="TestWebApi_InstanceCount" Value="1" />
    <Parameter Name="TestServiceName" Value="TestService" />
    <Parameter Name="TestService_InstanceCount" Value="-1" />
  </Parameters>
</Application>

在应用程序部署期间,您只需指定要使用的文件。现在要在服务中使用配置,您需要为每个服务修改 PackageRoot/Config/Settings.xml 文件:

<?xml version="1.0" encoding="utf-8" ?>
<Settings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2011/01/fabric">
  <Section Name="General">
    <Parameter Name="Environment" Value=""/>
    <Parameter Name="TestServiceName" Value=""/>
  </Section>
</Settings>

同样,您没有在此处指定值,它们将从 ApplicationManifest 中获取。您只需告诉您要将哪一个用于特定服务。

现在是代码。我创建了帮助类来检索配置值:

public class ConfigSettings : IConfigSettings
{
    public ConfigSettings(StatelessServiceContext context)
    {
        context.CodePackageActivationContext.ConfigurationPackageModifiedEvent += this.CodePackageActivationContext_ConfigurationPackageModifiedEvent;
        UpdateConfigSettings(context.CodePackageActivationContext.GetConfigurationPackageObject("Config").Settings);
    }

    private void CodePackageActivationContext_ConfigurationPackageModifiedEvent(object sender, PackageModifiedEventArgs<ConfigurationPackage> e)
    {
        this.UpdateConfigSettings(e.NewPackage.Settings);
    }

    public string Environment { get; private set; }
    public string TestServiceName { get; private set; }

    private void UpdateConfigSettings(ConfigurationSettings settings)
    {
        var generalSectionParams = settings.Sections["General"].Parameters;
        Environment = generalSectionParams["Environment"].Value;
        TestServiceName = generalSectionParams["TestServiceName"].Value;
    }
}

public interface IConfigSettings
{
    string Environment { get; }
    string TestServiceName { get; }
}

此类还有一个事件订阅,如果在服务运行时更改配置,它将更新配置。

剩下的就是ConfigSettings在启动期间使用服务上下文初始化你,并将其添加到内置的 ASP.NET CORE 容器中,以便你可以在其他类中使用它:

.ConfigureServices(services => services
    .AddSingleton<IConfigSettings>(new ConfigSettings(serviceContext)))

编辑:

一旦你在 asp.net core IoC Container 中有你的配置,你就可以通过构造函数注入来使用它,如下所示:

public class TestClass
{
    private readonly IConfigSettings _config;

    public TestClass(IConfigSettings config)
    {
        _config = config;
    }

    public string TestMethod()
    {
        return _config.TestServiceName;
    }
}

推荐阅读