Matthew Verstraete
Matthew Verstraete

Reputation: 6781

Reading from appsettings.json file gives NullReferance Error

I am trying to read some settings from my appsettings.json file but am getting a NullReferenceException. Using different SO posts as well as a few blogs I found on google I built the code and it all seems right, no compile errors and intillisense all works so I am not sure what I missed or did wrong.

Startup.CS:

public class Startup
{
    public IConfigurationRoot Configuration { get; set; }

    public Startup(IHostingEnvironment env)
    {
        //Set up configuration sources.
        var builder = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();

        Configuration = builder.Build();
    }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
        services.AddCaching();
        services.Configure<ApplicationSettingsModel>(Configuration.GetSection("AppSettings"));
        services.AddScoped<IApplicationSettings, ApplicationSettings>();

        services.AddSession(o =>
        {
            o.IdleTimeout = TimeSpan.FromSeconds(10);
        });
    }

    // 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();
        }

        app.UseExceptionHandler("/Error/ServerError");
        app.UseIISPlatformHandler();
        app.UseSession();
        app.UseStaticFiles();
        app.UseStatusCodePagesWithReExecute("/Error/PageNotFound");
        app.UseMvc();
    }

    // Entry point for the application.
    public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}

IApplicationSettings:

public interface IApplicationSettings
{
    IOptions<ApplicationSettingsModel> AppSettings { get; }
}

ApplicationsSettings.cs:

public class ApplicationSettings : IApplicationSettings
{
    protected readonly IOptions<ApplicationSettingsModel> _AppSettings;

    public ApplicationSettings(IOptions<ApplicationSettingsModel> AppSettings)
    {
        _AppSettings = AppSettings;
    }

    public IOptions<ApplicationSettingsModel> AppSettings
    {
        get
        {
            return _AppSettings;
        }
    }

    public string GetAppVersion()
    {
        return _AppSettings.Value.AppVersion;
    }
}

Model:

public class ApplicationSettingsModel
{
    public string AppVersion { get; set; }
    public string BugZillaAPIKey { get; set; }
    public string EmailUser { get; set; }
    public string EmailPass { get; set; }
}

Class making the call:

public class EHAL
{
    private static IApplicationSettings _config;

    public EHAL(IApplicationSettings config)
    {
        _config = config;
    }

    public static string Test()
    {
        return _config.AppSettings.Value.AppVersion;
    }
}

It is when I try to run return _AppSettings.Value.AppVersion; that the error is appearing. From the SO posts and blogs I think I am doing everything right but obviously I am screwing something up, just not sure what.

Upvotes: 2

Views: 1452

Answers (1)

mcbowes
mcbowes

Reputation: 798

I'm not 100% sure what exactly you are trying to do, but you should be able to let the DI container handle the constructor injection, I made a small test app to inject the test class into a controller for example....

Change your test class to

public class test : Itest
{
    protected readonly IOptions<AppSettings> _AppSettings;

    public test(IOptions<AppSettings> AppSettings)
    {
        _AppSettings = AppSettings;
    }

    public IOptions<AppSettings> AppSettings
    {
        get
        {
            return _AppSettings;
        }
    }

    public string GetAppVersion()
    {
        return _AppSettings.Value.AppVersion;
    }
}

Add an interface Itest

public interface Itest
{
    IOptions<AppSettings> AppSettings { get; }
}

Add this a new line in your Startup.cs

services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
services.AddScoped<Itest, test>();

Now in your controller you can do the following:

 public class HomeController : Controller
    {
        private readonly Itest _config;
        public HomeController(Itest config)
        {
            _config = config;
        }
        public IActionResult Index()
        {
            var a = _config.AppSettings.Value.AppVersion;
            return View();
        }
    }

which will just inject an instance of your test class into the controller so you can use it during processing of the request.

Again, not 100% sure where you are going with this, this is an example of how you can get this to work. Hope that helps!

EDIT: You have some other options as well, you could just inject IOptions<AppSettings> into the controller constructor and just create an instance of the test class passing in the injected IOptions<AppSettings> as well. That way you could get rid of the Itest interface and the extra config code in Startup.cs, just another thought.

EDIT: So, I really think you should take a look at dependency injection, it really is the way to go. But if you really don't want to go the DI root, you can do something like this, (change your static class to look like this):

public class test
{
    static IConfigurationSection _Settings;

    static test()
    {

        IConfiguration _config = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")
            .Build();

        _Settings = _config.GetSection("AppSettings");
    }

    public static string GetAppVersion()
    {
        return _Settings["AppVersion"];
    }
}

Then you can make a call like so:

var a = test.GetAppVersion();

Although I'm not a big fan of doing this with statics I tried to keep in the spirit of what you were trying to do. Really, DI is the way to go moving forward, strongly suggesting that you go that direction in future.

Upvotes: 1

Related Questions