locked
Reading appsettings.json from controllers RRS feed

  • Question

  • User-1458727574 posted

    I need to store some settings in appsettings.json. I've read and re-read several pages and I've got almost nowhere, other than confused. I've read the MS articles and I'm still having trouble. Here is an example appsettigns.json:

    {
        "appSettings": {
            "UserId": "User1",
            "UserPassword": "Password123",
            "IVersion": "1.0",
            "EPName": "TargetAPI",
            "Hostname": "localhost",
            "UserHTTPS": "N",
            "LogFilePath": "./Logs/"
        }
    }

    Here is the Startup class:

        public class Startup
        {
            public IConfigurationRoot Configuration { get; set; }
    
            public void ConfigureServices(IServiceCollection services)
            {
                var mvcBuilder = services.AddMvc();
                mvcBuilder.AddXmlSerializerFormatters();
    
                services.AddOptions();
    
                services.Configure<IISOptions>(options =>
                {
                    options.AutomaticAuthentication = false;
                    options.ForwardClientCertificate = false;
                });
    
                services.Configure<ACLApplicationSettings>(Configuration.GetSection("ACLApplicationSettings");
            }
    
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }            
    
                app.UseMvc();
                
                app.Run(async (context) =>
                {
                    await context.Response.WriteAsync("No function called.");
                });
            }
        }

    The controller has this at the top:

        [Route("api/[controller]")]
        [ApiController]
        public class CustomersController : ControllerBase
        {
            private readonly IOptions<ACLApplicationSettings> settings;
    
            public CustomersController(IOptions<ACLApplicationSettings> config)
            {
                settings = config;
            }
    

    Now later in the class I would expect to be able to access the settings by typing:

    settings.Value.ACLSettings.UserId

    If I write the above line below the line in the constructor I can access the values. Outside of the constructor I cannot. What is going on? All I want to do is read settings that are held in an external file!

    Friday, July 6, 2018 2:23 PM

Answers

  • User-1458727574 posted

    I found the problem though as it as the only difference in terms of structure and that is the location of the appsettings.json. In mine, I had moved it (and several others) into ./Config/appsettings.json.

    It seems that despite my moving it, that it cannot be in anywhere other than the application root. I move it there and it works. Didn't see that in any of the documentation!!

    Hours of wasted time!

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, July 11, 2018 11:31 AM

All replies

  • User475983607 posted

    Something is not right with the source code and explanation of operation.  First, there is no section named ACLApplicationSettings in the posted code  I assume the syntax errors is copy and paste mistake.  Do you want to read an external file or appsettings.json or both?  Do you simply want to pass the configuration service to the constructor or do you wnat to populate a type?

    Friday, July 6, 2018 2:39 PM
  • User-1458727574 posted

    I forgot to paste the class I'd created to hold the config data in appsettings.json.

        public class ACLSettings
        {
            public string UserId { get; set; }
            public string UserPassword { get; set; }
            public string IVersion { get; set; }
            public string EPName { get; set; }
            public string HostName { get; set; }
            public string UserHTTPS { get; set; }
            public string LogFilePath { get; set; }
        }
    
        public class ACLApplicationSettings
        {
            public ACLSettings ACLSettings { get; set; }
        }

    My code I posted is my effort to try and get working from the numerous docs I've read online in getting settings read from the appsettings.json. When the web service starts up, I need it to be able to read the values so that I can access them within the application. It's just configuration information so it isn't hardcoded in, such that when I deploy on a different machine, I can put in different values. If my approach isn't right, I'm happy to remove it.

    Friday, July 6, 2018 3:01 PM
  • User475983607 posted

    Below is an example that used appsetting.json.  

    The class that holds the configuration values.

    namespace CoreApi.Settings
    {
        public class AppSettings
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }
    }

    appsetting.json

    {
      "AppSettings": {
        "Id": 1,
        "Name": "Hello World"
      },
      "Logging": {
        "LogLevel": {
          "Default": "Warning"
        }
      },
      "AllowedHosts": "*"
    }

    The controller.

        [Route("api/[controller]")]
        [ApiController]
        public class ValuesController : ControllerBase
        {
            private readonly IConfiguration _configuration;
            private AppSettings _appSettings;
            public ValuesController(IConfiguration configuration)
            {
                _configuration = configuration;
                _appSettings = configuration.GetSection("AppSettings").Get<AppSettings>();
            }
            // GET api/values
            [HttpGet]
            public ActionResult<IEnumerable<string>> Get()
            {
                return new string[] { _appSettings.Id.ToString(), _appSettings.Name };
            }

    The results

    [
      "1",
      "Hello World"
    ]

    the program file and startup are vanilla and not changed from the default template.

        public class Program
        {
            public static void Main(string[] args)
            {
                CreateWebHostBuilder(args).Build().Run();
            }
    
            public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
                WebHost.CreateDefaultBuilder(args)
                    .UseStartup<Startup>();
        }
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            // 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, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    app.UseHsts();
                }
    
                app.UseHttpsRedirection();
                app.UseMvc();
            }
        }

    Friday, July 6, 2018 3:03 PM
  • User-1458727574 posted

    Some questions at the end but first, here is what I have.

    My class that holds the configuration values:

        public class ACLSettings
        {
            public string UserId { get; set; }
            public string UserPassword { get; set; }
            public string IVersion { get; set; }
            public string EPName { get; set; }
            public string HostName { get; set; }
            public string UserHTTPS { get; set; }
            public string LogFilePath { get; set; }
        }

    appsettings.json

    {
        "ACLSettings": {
            "UserId": "ADMIN",
            "UserPassword": "Password123",
            "IVersion": "1.0",
            "EPName": "SWeb",
            "HostName": "localhost",
            "UserHTTPS": "N",
            "LogFilePath": "./ApiLogs/"
        }
    }

    The controller:

        [Route("api/[controller]")]
        [ApiController]
        public class CustomersController : ControllerBase
        {
            private readonly IConfiguration appConfiguration;
            private ACLSettings aCLSettings;
    
            public CustomersController(IConfiguration configuration)
            {
                appConfiguration = configuration;
                aCLSettings = configuration.GetSection("ACLSettings").Get<ACLSettings>();
            }
    
            private static string responsePayload = "";
            private static string serverName = "";
    
            // POST api/<controller>
            [HttpPost("")]
            public string Post([FromBody] customersT customers, [FromQuery] string s = "")
            {
                string WebAPIURI = ((aCLSettings.UserHTTPS == "Y") ? "https://" : "http://") +
                                            aCLSettings.HostName + "/" +
                                            aCLSettings.EPName + "/v" +
                                            aCLSettings.IVersion + "/-/";
    
    // additional code to deal with the post
    ...
    }

    Start up:

        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            public void ConfigureServices(IServiceCollection services)
            {
                var mvcBuilder = services.AddMvc();
                mvcBuilder.AddXmlSerializerFormatters();
    
                services.Configure<IISOptions>(options =>
                {
                    options.AutomaticAuthentication = false;
                    options.ForwardClientCertificate = false;
                });
            }
    
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }            
    
                app.UseMvc();
                
                app.Run(async (context) =>
                {
                    await context.Response.WriteAsync("No function was called.");
                });
            }
        }

    Program:

        public class Program
        {
            public static void Main(string[] args)
            {
                CreateWebHostBuilder(args).Build().Run();
            }
    
            public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
                WebHost.CreateDefaultBuilder(args)
                    .UseKestrel()
                    .UseContentRoot(System.IO.Directory.GetCurrentDirectory())
                    .UseIISIntegration()
                    .UseStartup<Startup>();
        }

    The output:

    System.NullReferenceException
      HResult=0x80004003
      Message=Object reference not set to an instance of an object.
      Source=ACLWebApi
      StackTrace:
       at ACLWebApi.Controllers.CustomersController.Post(customersT customers, String s) in E:\Projects\ACLWebApi\ACLWebApi\Controllers\CustomersController.cs:line 34
       at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
       at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
       at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeActionMethodAsync>d__12.MoveNext()
    

    This happens on the first line of code in the Post handler. As soon as it tries to build the string called WebAPIURI. So I thought, ok, I'm not creating a new object called aCLSettings, so I changed the line in the constructor from:

            private ACLSettings aCLSettings;

    to:

            private ACLSettings aCLSettings = new ACLSettings();

    Still no joy. When I get to construct the WebAPIURI string from the settings, aCLSettings is always null so I get a NullReferenceException.

    Another question. How come when I want to access the values in aCLSettings, I can do it when I am in a function within the controller, but outside of a function I cannot? This isn't too important, just curious.

    Monday, July 9, 2018 9:44 AM
  • User36583972 posted

    Hi friend,

    You can refrer the following samples to read values from "appsettings.json".

    Setting And Reading Values From "appsettings.json" In .NET Core
    https://www.c-sharpcorner.com/article/setting-and-reading-values-from-app-settings-json-in-net-core/

    Read configuration in the controller: .Net Core Quick posts
    https://neelbhatt.com/2018/02/11/read-configuration-in-the-controller-net-core-quick-posts/

    Best Regards,

    Yong Lu

    Wednesday, July 11, 2018 9:10 AM
  • User-1458727574 posted

    As I said, I have read lots of resources, these included. Some pages say I don't need to add the constructor in Startup in ASP.NET core 2.x and I'm using 2.1. If I don't the line

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

    in ConfigureServices in Startup doesn't work.

    Once in my controller, I have a constructor as below:

           public CustomersController(IConfiguration Configuration)
            {
                appConfiguration = Configuration;
                aCLSettings = appConfiguration.GetSection("ACLSettings").Get<ACLSettings>();
            }

    aCLSettings is ALWAYS null, no matter what I try. As soon as I do a post to the web service, the controller picks up the request, and the first line makes up a target URL using data from the appsettings.json file and as aCLSettings is always null because the values are not being read into it, I get an rror when accessing the options which is a NullReferenceException.

    I cannot believe it is so stupidly difficult to read configuration files!

    Wednesday, July 11, 2018 10:03 AM
  • User-1458727574 posted

    I found the problem though as it as the only difference in terms of structure and that is the location of the appsettings.json. In mine, I had moved it (and several others) into ./Config/appsettings.json.

    It seems that despite my moving it, that it cannot be in anywhere other than the application root. I move it there and it works. Didn't see that in any of the documentation!!

    Hours of wasted time!

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, July 11, 2018 11:31 AM