0

I'm unable to retrieve the value from appsettings.json, when I run the code below, I get an error

System.NullReferenceException: 'Object reference not set to an instance of an object.

appSettings.json

"MySettings": {
"ConnectionString": "",
"Provider": "Microsoft.EntityFrameworkCore.SqlServer" }

Startup.cs

public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();
        Configuration = builder.Build();
    }


    public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddMvc();
        services.Configure<MySettings>(Configuration.GetSection("MySettings"));
    }

MySettings.cs

public class MySettings 
{
    public static string ConnectionString { get; set; }

    public static string Provider { get; set; }
}

TestDriveDatabase.cs

public class TestDriveDatabase
{
    private IDatabase objDLOperation;

    public TestDriveDatabase(string strConnectionstring)
    {
        objDLOperation = GetDataLayerInstance(strConnectionstring);
    }
    public IDatabase GetDataLayerInstance(string strConnectionstring)
    {
        IDatabase objInstance = null;
        var provider = MySettings.Provider;

        if (provider == "Microsoft.EntityFrameworkCore.SqlServer")
        {
            objInstance = new SQLDatabase(strConnectionstring);
        }
        else if (provider == "Npgsql.EntityFrameworkCore.PostgreSQL")
        {
            objInstance = new PostgreDatabase(strConnectionstring);
        }

        return objInstance;
    }
}

Unfortunately the mapping from appsettings.json to MySettings is not happening and the variable provider always remains null. Whats wrong here ?

izengod
  • 1,116
  • 5
  • 17
  • 41
  • remove `static` modifier from property. Pass `MySettings` via DI. – Ilya Chumakov May 02 '17 at 11:46
  • If you remove static, you can't simply access MySettings.Provider – izengod May 02 '17 at 11:47
  • Of course. How it should work: http://stackoverflow.com/q/43679665/5112433 – Ilya Chumakov May 02 '17 at 11:48
  • @izengod: Mapping only works to instance properties, not to static properties. Second, you are supposed to inject the `MySettings` class into your services (via `IOptions`) instead accessing it's static properties – Tseng May 02 '17 at 11:54
  • @Tseng I was trying out without DI since I am not calling it inside a controller. – izengod May 02 '17 at 11:59
  • DI works everywhere, as long as the class is resolved by DI at some point. And accessing static values like you did is very bad, for both testability and decoupling – Tseng May 02 '17 at 12:00

1 Answers1

1

First remove the static keyword, you can't map configuration values to static properties

public class MySettings 
{
    public string ConnectionString { get; set; }

    public string Provider { get; set; }
}

Second, inject MySettings into your TestDriveDatabase.

public class TestDriveDatabase
{
    private IDatabase objDLOperation;
    private readonly MySettings settings;

    public TestDriveDatabase(IOptions<MySettings> mySettings)
    {
        this.settings = mySettings.Value;
        objDLOperation = GetDataLayerInstance(strConnectionstring);
    }
    public IDatabase GetDataLayerInstance(string strConnectionstring)
    {
        IDatabase objInstance = null;
        var provider = settings.Provider;

        if (provider == "Microsoft.EntityFrameworkCore.SqlServer")
        {
            objInstance = new SQLDatabase(settings.Connectionstring);
        }
        else if (provider == "Npgsql.EntityFrameworkCore.PostgreSQL")
        {
            objInstance = new PostgreDatabase(settings.Connectionstring);
        }

        return objInstance;
    }
}
Tseng
  • 61,549
  • 15
  • 193
  • 205
  • cool! but what shall I pass in TestDriveDatabase ctor while creating an instance ? since it takes an IOptions object. I need to call another method of TestDriveDatabase inside controller. – izengod May 02 '17 at 12:14
  • 3
    Use Dependency Injection all the way. The only time you should use the `new` keyword is when you create models or inside factory methods. All other services should be done via DI. That's the whole point of using DI in the first place. i.e. when you define `TestDriveDatabase` in your Controller's ctor, then `IOption` will also be resolved by DI, because `TestDriveDatabase gets resolved by it too. – Tseng May 02 '17 at 12:19