Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to bind configuration to stateless/readonly model in .NET Core?

Normally, we would have some model

public class ConnectionStrings
{
    public string Sql { get; set; }
    public string NoSql { get; set; }
}

then we have something in appsettings.json as follow:

"ConnectionStrings": {
    "Sql": "some connection string",
    "NoSql": "some other connection string"
}

Then I bind the model as follows:

services.Configure<ConnectionStrings>(
            options => Configuration.GetSection("ConnectionStrings").Bind(options));

All works perfectly, but it doesn't make sense for my model to be mutable since it is holding important information. After all, configurations are static information, so once my model is read, it should stay like it is.

Is there any other way of doing this more safely?

like image 755
kuskmen Avatar asked Jul 28 '17 16:07

kuskmen


People also ask

What is Configurationbuilder in .NET Core?

Used to build key/value-based configuration settings for use in an application.

How do I use IOptions in NET Core 6?

IOptions is singleton and hence can be used to read configuration data within any service lifetime. Being singleton, it cannot read changes to the configuration data after the app has started. Run the app and hit the controller action. You should be able to see the values being fetched from the configuration file.

Is Ioption a singleton?

IOptionsMonitor is a Singleton service that retrieves current option values at any time, which is especially useful in singleton dependencies.

What does configuration bind do?

Bind(IConfiguration, String, Object)Attempts to bind the given object instance to the configuration section specified by the key by matching property names against configuration keys recursively.


2 Answers

As an alternative, for version 2.1+, you can now bind to non-public properties by specifying to do so with BinderOptions:

services.Configure<ConnectionStrings>(options => 
        Configuration.GetSection("ConnectionStrings")
                .Bind(options, c => c.BindNonPublicProperties = true));

or to just get them:

var connectionStrings = Configuration.GetSection("ConnectionStrings")
        .Get<ConnectionStrings>(c => c.BindNonPublicProperties = true);
like image 56
George Mulligan Avatar answered Oct 14 '22 05:10

George Mulligan


code like this uses underhood the ConfigurationBinder that expects public properties. From BindProperty method:

// We don't support set only, non public, or indexer properties
if (property.GetMethod == null ||
   !property.GetMethod.IsPublic ||
   property.GetMethod.GetParameters().Length > 0)
{
   return;
}

As a workaround, I may suggest populating your class manually. Take the following as an example:

public class ConnectionStrings
{
    public ConnectionStrings(string sql, string noSql)
    {
        Sql = sql;
        NoSql = noSql;
    }

    public string Sql { get; private set; }
    public string NoSql { get; private set; }
}

and then in ConfigureServices method:

var sqlValue = Configuration.GetValue<string>("ConnectionStrings:Sql", string.Empty);
var noSqlValue = Configuration.GetValue<string>("ConnectionStringsApp:NoSql", string.Empty);

services.Configure<ConnectionStrings>(
           options => new ConnectionStrings(sqlValue, noSqlValue));
like image 43
Set Avatar answered Oct 14 '22 04:10

Set