I am new to .Net Core and trying to get a value from the appsettings.json
file but I have missed something very basic. Please let me know what I have done wrong... Here is the code...
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");
Both the above lines are returning null values for both GetSection
and GetValue
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"
}
Accessing the configuration in the Controller works a little different than in the Startup.cs. I did this a while back, just follow these steps:
Nuget: Microsoft.Extensions.Configuration.Binder
Put all the Configuration you want to access in your Controller into one Section, eg "EmailSettings":
appsettings.json
{
"EmailSettings": {
"EmailTemplatesPath": "EmailTemplates",
"Email": "aa@aa.com"
}
}
Then Create a Class in your Web API Project called EmailSettings.cs
:
EmailSettings.cs
public class EmailSettings
{
public string EmailTemplatesPath { get; set; }
public string Email { get; set; }
}
Then bind your Config values to an Instance of the EmailSettings
Class in Startup.cs
and add that Object to the Dependency Injection Container:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
...
EmailSettings emailSettings = new EmailSettings();
Configuration.GetSection("EmailSettings").Bind(emailSettings);
services.AddSingleton(emailSettings);
}
Now you can request your Configuration in the Api Controller by simply adding it to the Constructor like this:
Web API Controller
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
EmailSettings _emailSettings;
public ValuesController(EmailSettings emailSettings)
{
_emailSettings = emailSettings;
}
....
}
Just tried this again in my current Project (.NET Core 2.2 Web Api) and it worked. I put a Breakpoint in the ValuesController Constructor and the _emailSettings Object contained the values from the appsettings.json
file. You should be able to just Copy & Paste this! Have fun! :)
When hosting in-process inside of IIS (or IIS Express), Directory.GetCurrentDirectory()
will return a different path to that which is returned when running out-of-process . Up until ASP.NET Core 2.1, IIS-based hosting was always out-of-process, but ASP.NET Core 2.2 introduces the ability to run in-process (which is the default when creating a new project).
When running out-of-process, Directory.GetCurrentDirectory()
will return the path to your ASP.NET Core application itself, whereas when running in-process, it will return the path to IIS (or IIS Express, eg "C:\\Program Files\\IIS Express").
From your question, the relevant code is this:
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
})
Here, before you make a call to SetBasePath
, the IConfigurationBuilder
has already been set up to use the correct path. Your call itself is overriding this path, setting it to eg "C:\\Program Files\\IIS Express". With this overridden base-path, your appsettings.json
et al files are no longer found, as they do not live in eg "C:\\Program Files\\IIS Express", and so no configuration is loaded from these files.
The solution is simply to remove your call to ConfigureAppConfiguration
so that the base-path does not get overridden. I realise you've already discovered this, but I wanted to make sure you had an explanation as to what was going wrong here.
You made a simple mistake and forgot to add "Email" into "EmailSettings". Update your json as shown below and get the Email with config.GetSection("EmailSettings")["Email"];
"EmailSettings": {
"EmailTemplatesPath": "EmailTemplates",
"Email": "aa@aa.com"
},
Hope this solves your problem.
Edit:
If you wanna get those values from appsettings to anything other than startup, you should load those config values into a settings class and then inject appropiate IOptions instance to the method constructor in which you want to use those settings. To do so, please see my answer here .
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();
}
}
Controller Class
You need to use Bind() method to get the value from section.
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");
Email Setting Model:- (Property name should match with config Key)
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"
}
While others have solved this problem, if you want to leave your startup services code as is, just change your Web API controller to the following:
private readonly EmailSettings _emailSettings;
public EmailController(IOptions<EmailSettings> emailSettings)
{
_emailSettings = emailSettings.Value;
}
The emphasis is on the .Value . That's why your code is returning null. I would also suggest changing program.cs back to it's default. And to use this in an action method, just do the following:
_email.settings.EmailTemplatesPath
One last thing - make sure your EmailSettings class structure is the exact same as your json.
You can do something like this
services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));
services.AddTransient(p => p.GetRequiredService<IOptions<EmailSettings>>().Value);
and initialize EmailSettings object via constructor DI.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.