configuration.getValue或configuration.getsection始终返回null

6

我是一个新手,正在尝试从appsettings.json文件中获取值,但我错过了一些非常基本的东西。请告诉我我做错了什么......以下是代码...

Program.cs

 WebHost.CreateDefaultBuilder(args)
 .ConfigureAppConfiguration((hostingContext, config) =>
 {
      config.SetBasePath(Directory.GetCurrentDirectory());
 })

Startup.cs

public IConfiguration Configuration { get; private set; }
public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
    services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));
}

Web API Controller

private readonly IConfiguration config;

public EmailController(IConfiguration configuration)
{
    if (configuration != null)
    {
        config = configuration;
    }
}

Action Method

var emailTemplatesRelativePath = config.GetSection("EmailSettings");
var email = config.GetValue<string>("Email");

以上两行代码都返回GetSectionGetValue的null值。

appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Trace",
      "Microsoft": "Information"
    }
  },
  "ConnectionStrings": {
    "FCRContext": "server=xxx;database=xxx;user id=xxx;password=xxx"
  },
  "AllowedHosts": "*",
  "EmailSettings": {
    "EmailTemplatesPath": "EmailTemplates"
  },
  "Email": "aa@aa.com"
}

通常情况下,您应该在 Startup.cs 中初始化 IConfiguration,而不是在 Program.cs 中。如果您按照您描述的方式得到了 null 值,则说明有问题。请展示 Startup.cs - Felix
我正在关注这个链接:https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/index?view=aspnetcore-2.2。我也尝试了“选项模式”,但它没有起作用... - Naveed Butt
1
目前使用 .Net Core 2.2 并且使用 IIS Express。 - Naveed Butt
6个回答

7

在控制器中访问配置与在Startup.cs中略有不同。我以前做过这个,只需按照以下步骤操作:

Nuget:Microsoft.Extensions.Configuration.Binder

将您想要在控制器中访问的所有配置放入一个部分中,例如“EmailSettings”:

appsettings.json

{
  "EmailSettings": {
    "EmailTemplatesPath": "EmailTemplates",
    "Email": "aa@aa.com"
  }
}

请在您的Web API项目中创建一个名为EmailSettings.cs的类: EmailSettings.cs
public class EmailSettings
{
    public string EmailTemplatesPath { get; set; }
    public string Email { get; set; }
}

然后将您的配置值绑定到 Startup.csEmailSettings 类的实例,并将该对象添加到依赖注入容器中:

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    ...
    EmailSettings emailSettings = new EmailSettings();
    Configuration.GetSection("EmailSettings").Bind(emailSettings);
    services.AddSingleton(emailSettings);
}

现在您可以通过将配置添加到构造函数中,轻松地在Api控制器中请求您的配置,如下所示: Web API控制器
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    EmailSettings _emailSettings;

    public ValuesController(EmailSettings emailSettings)
    {
        _emailSettings = emailSettings;
    }
....
}

我在我的当前项目(.NET Core 2.2 Web Api)中再次尝试了这个方法,它很有效。我在ValuesController构造函数中设置了一个断点,_emailSettings对象包含了appsettings.json文件中的值。你只需要复制并粘贴即可!祝你玩得愉快! :)


不,这两行代码是为了表明GetSectionGetValue都没有返回任何值。 - Naveed Butt
已更新以在控制器中运行。我亲自测试过,你也可以试试 :) - Robert Bantele

4
当在IIS(或IIS Express)中托管进程内时,Directory.GetCurrentDirectory()返回的路径与运行进程外时返回的路径不同。直到ASP.NET Core 2.1为止,基于IIS的托管始终是进程外的,但ASP.NET Core 2.2引入了在进程内运行的功能(这是创建新项目时的默认设置)。
当运行进程外时,Directory.GetCurrentDirectory()将返回您的ASP.NET Core应用程序本身的路径,而当运行进程内时,它将返回IIS(或IIS Express)的路径,例如"C:\Program Files\IIS Express"。
从您的问题中,相关代码如下:
WebHost.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((hostingContext, config) =>
    {
        config.SetBasePath(Directory.GetCurrentDirectory());
    })

在调用 SetBasePath 之前,IConfigurationBuilder 已经被设置为使用正确的路径。你的调用正在覆盖这个路径,将它设置为例如 "C:\Program Files\IIS Express"。由于这个被覆盖的基路径,你的 appsettings.json 等文件不再存在于例如 "C:\Program Files\IIS Express" 中,因此没有从这些文件中加载配置。
解决方案很简单,只需删除对 ConfigureAppConfiguration 的调用,以便不覆盖基路径。我知道你已经发现了这一点,但我想确保你知道这里出了什么问题。

将此部署到1)旧版本的IIS或2)最新版本的IIS时是否有任何影响?如果我们为项目设置了“in-process”,那么即使在创建项目时它在项目中,我们也永远不会使用config.SetBasePath吗?如果是这样,我想这只是因为微软还没有更新模板。 - Ensunder

3
你犯了一个简单的错误,忘记在“EmailSettings”中添加“Email”。按下面所示更新你的json,并使用 config.GetSection("EmailSettings")["Email"]; 获取电子邮件。
"EmailSettings": {
    "EmailTemplatesPath": "EmailTemplates",
    "Email": "aa@aa.com"
  },

希望这能解决你的问题。
编辑:
如果你想从appsettings获取那些值并将它们加载到除startup以外的任何地方,你应该将这些配置值加载到一个设置类中,然后在你想使用这些设置的方法构造函数中注入适当的IOptions实例。要做到这一点,请参见我在这里的答案。

这是两个单独的语句,表明它们都没有返回任何值。 - Naveed Butt
你可以通过该链接查看我的答案,并使用settings类从appsetting.json获取这些值,并通过IOptions将其注入到控制器中。https://dev59.com/wrDla4cB1Zd3GeqP_qyt#53904527 - Hasan

1

Program.cs

public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();

        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
             .UseStartup<Startup>();
    }

Startup.cs:

public partial class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IAntiforgery antiforgery)
        {
            app.UseMvcWithDefaultRoute();
        }
    }

控制器类

enter image description here

你需要使用Bind()方法来获取部分的值。
EmailSetting option = new EmailSetting();
            //You need to bind the section with data model, 
            //it will automatically map config key to property of model having same name
            config.GetSection("EmailSettings").Bind(option);

            //Alternative to this you can read nested key using below syntax
            var emailTemplatesPath = config["EmailSettings:EmailTemplatesPath"];
            var emailInEmailSettings = config["EmailSettings:Email"];
            // If email key is not nested then you can access it as below
            var email = config.GetValue<string>("EmailOutside");

电子邮件设置模型:(属性名称应与配置键匹配)

public class EmailSetting
    {
        public string EmailTemplatesPath { get; set; }
        public string Email { get; set; }
    }

Appsetting.json:-

    {
       "AllowedHosts": "*",
        "EmailSettings": {
            "EmailTemplatesPath": "EmailTemplates",
            "Email": "aa@aa.com"
          },
          "EmailOutside": "aa@aa.com"
        }

这个 config["EmailSettings:EmailTemplatesPath"] 仍然返回 null - Naveed Butt
请尝试创建一个简单的MVC项目,其中包含一个控制器来读取配置文件。我已经更新了答案并在其中添加了代码示例。请尽量保持这个虚拟项目非常简单,在管道中除了MVC之外不要添加任何中间件。 - Ashish Mishra
谢谢。那很有帮助。我创建了一个空应用程序,它正确返回了配置值。然后我比较了两个 program.cs 文件,问题就在这一行上,我必须添加:.ConfigureAppConfiguration((hostingContext, { config.SetBasePath(Directory.GetCurrentDirectory()); }) - Naveed Butt
不知道为什么会出现这个问题。MSDN上说我需要添加那个... https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/index?view=aspnetcore-2.2 - Naveed Butt
我尝试了带和不带ConfigureAppConfiguration()的情况,在两种情况下代码都可以正常工作。 - Ashish Mishra

1

虽然其他人已经解决了这个问题,但如果您想保留创业服务代码不变,请将您的Web API控制器更改为以下内容:

private readonly EmailSettings _emailSettings;

public EmailController(IOptions<EmailSettings> emailSettings)
{
    _emailSettings = emailSettings.Value;
}

重点在于.Value。这就是为什么你的代码返回null的原因。我还建议将program.cs改回默认设置。要在操作方法中使用它,只需执行以下操作:
_email.settings.EmailTemplatesPath

最后一件事 - 确保您的EmailSettings类结构与您的json完全相同。


0
你可以像这样做
services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));
services.AddTransient(p => p.GetRequiredService<IOptions<EmailSettings>>().Value);

并通过构造函数 DI 初始化 EmailSettings 对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接