10
votes

I added a CustomSettings section keys in appSettings.json in ASP.NET Core project:

{
  "ConnectionStrings": {
    "DefaultConnectionString": "Data Source=..."
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "CustomSettings": {
    "Culture": "es-CO"
  }
}

I've not been able to load Culture key in following controller:

public AccountController(
            UserManager<ApplicationUser> userManager,
            SignInManager<ApplicationUser> signInManager,
            IEmailSender emailSender,
            ILogger<AccountController> logger,
            IConfiguration configuration)
{
   Response.Cookies.Append(
                    CookieRequestCultureProvider.DefaultCookieName,
                    CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(configuration.GetSection("CustomSettings")["Culture"])),
                    new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) }
            );
}

No matter if I do following, always they return NULL: configuration.GetSection("CustomSettings")["Culture"]; configuration.GetSection("CustomSettings").GetValue("Culture");

I tried help based in ASP.NET Core: Step by Step Guide to Access appsettings.json in web project and class library and I've created CustomSettings class with string Culture property and injecting in Startup as follows:

        // Load Custom Configuration from AppSettings.json
        services.Configure<Models.CustomSettings>(Configuration.GetSection("CustomSettings"));

Accesing by inject IOptions customSettings, the value of customSettings.Value.Culture returns NULL.

First Question: ¿What am I doing wrong or what is missing?

Second Question: ¿Why doing following in Index of HomeController throws an exception?

public class HomeController : Controller
{
   public IActionResult Index(IConfiguration configuration)
   {
   }
}

Exception:

An unhandled exception occurred while processing the request. InvalidOperationException: Could not create an instance of type 'Microsoft.Extensions.Options.IOptions`1[[OmniMerchant.Models.CustomSettings, OmniMerchant, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'. Model bound complex types must not be abstract or value types and must have a parameterless constructor.

Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder.CreateModel(ModelBindingContext bindingContext)

Third Question: I need to set Culture from Starting for all the app in background based on Culture property on appSettings.json, I read MSDN documentation, but I've not been able to achieve that, ¿How can I achieve this?

Thanks

6

6 Answers

7
votes

First create the modal that matches the appsetting section

public class CustomSettings
{
    public string Culture { get; set; }
}

Then register it in the ConfigureServices method in Startup.cs

services.Configure<CustomSettings>(Configuration.GetSection("CustomSettings"));

Then inject it using IOptions where its needed

AccountController(IOptions<CustomSettings> settings)
{
    _settings = settings.Value;
}
4
votes
  1. Why configuration section values are null?

By default there are two config files. For Release build and one for Debug. Have you checked that you actually editing the correct one (probably appsettings.Development.json)

  1. Why DI is not working.

In .NET Core basically you can use DI in two ways. By injecting it in constructor or directly in method. In the second option you have to use special attribute [FromServices]

4
votes

In your application properties -> Debug section -> Environment variables

If this is set ASPNETCORE_ENVIRONMENT: Development

It will use appsettings.Development.json

4
votes

TL:DR; Your appsettings.json file needs to be in the same working directory as your dll file.

You need to make sure that you are running the app from it's working directory.

For example, if your dll's are built to the bin folder, the following won't work:

cd bin
dotnet run app.dll

Because the appsettings.json file is not in the same folder as the dll that you are running from.

However if you are in the directory that the appsettings.json file is in, the current working directory will be set and that file will be read.

dotnet run bin/app.dll

If using VS Code launch.json you can set the cwd property to achieve this.

2
votes

I had problems reading from different configuration files until I added each of them specifically in the Startup constructor like below:

public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json")                //***
        .AddJsonFile("appsettings.development.json")    //***
        .AddEnvironmentVariables();

        Configuration = builder.Build();
}
0
votes

This is a bug I think but probably you can solve it by setting "HostingEnvironment.ContentRootPath" manualy.

Try to add the following code in the Startup method in Startup.cs:

if (env.EnvironmentName== "Production")
{
    env.ContentRootPath = System.IO.Directory.GetCurrentDirectory();
}

or hardcode path like this:

if (env.EnvironmentName == "Production")
{
    env.ContentRootPath = "/var/aspnetcore/...";
}

For example if your files located in "/var/aspnetcore/my_ASP_app", the startup method should be something like this:

public Startup(IHostingEnvironment env)
{
    if (env.EnvironmentName== "Production")
    {
        //env.ContentRootPath = "/var/aspnetcore/my_ASP_app";
        env.ContentRootPath = System.IO.Directory.GetCurrentDirectory();
    }
    //env.ContentRootPath = System.IO.Directory.GetCurrentDirectory();//you can write this line outside of IF block.
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
        .AddJsonFile("appsettings.Production.json", optional: true, reloadOnChange: true);

    Configuration = builder.Build();

}

It is better to use Directory.GetCurrentDirectory() instead of hardcoding.

This worked for me in Linux Ubuntu with nginx, but I don't know if it is applicable for your enviornment.