How to reference another value within the same appsettings.json file?
Asked Answered
E

4

6

I need database connection string in two places in appsettings.json.

Is it possible to introduce common variable or json-path related references into json file to avoid potencial problems?

It would be lovely to have it without touching c# code.

{
...
  "ConnectionStrings": {
    "Default": "Host=localhost;Database=db;Port=5432;Username=postgres;Password=postgres"
  },
  "Nlog": {
    "targets": {
      "database": {
        "type": "Database",
        "dbProvider": "Npgsql.NpgsqlConnection, Npgsql",
        "connectionString": "Host=localhost;Database=db;Port=5432;Username=postgres;Password=postgres",
...
      }
    }
...
}
Ericaericaceous answered 16/10, 2019 at 12:34 Comment(0)
M
5

NLog has the ability to lookup values in the appsettings.json. You can do it like this with ${configsetting}:

{
...
  "ConnectionStrings": {
    "Default": "Host=localhost;Database=db;Port=5432;Username=postgres;Password=postgres"
  },
  "Nlog": {
    "targets": {
      "database": {
        "type": "Database",
        "dbProvider": "Npgsql.NpgsqlConnection, Npgsql",
        "connectionString": "${configsetting:item=ConnectionStrings.Default}",
...
      }
    }
...
}

See also https://github.com/NLog/NLog/wiki/ConfigSetting-Layout-Renderer

Movable answered 19/10, 2019 at 17:32 Comment(1)
It works! Whats a pity that you cannot use it in general appsettings fileEricaericaceous
P
5

I've created a nuget package exactly for this! Check it out here: https://www.nuget.org/packages/TemplateFormattedConfiguration/

In your example you should do this:

{
...
    "ConnectionStrings": {
"Default": "Host=localhost;Database=db;Port=5432;Username=postgres;Password=postgres"
  },
  "Nlog": {
    "targets": {
      "database": {
        "type": "Database",
        "dbProvider": "Npgsql.NpgsqlConnection, Npgsql",
        "connectionString": "{ConnectionStrings:Default}",
...
      }
    }
...
}

And in your Startup.cs (or Program.cs) you'll add this:

        configuration.EnableTemplatedConfiguration();
Prynne answered 22/9, 2020 at 19:21 Comment(0)
C
0

No. There is no support for this. Two things, though:

  1. While the data being provided in each case is the same, the two things are not the same. It's not a duplication when both just happen to be using the same data source, as that may just as well not be the case.

  2. There's nothing magical about the ConnectionStrings section, except that it allows you to use the GetConnectionString sugar. You could just as well do something like:

    services.AddDbContext(o =>
        o.UseSqlServer(Configuration["Nlog:targets:database:connectionString"]));
    

    Whether or not that's appropriate is a separate discussion. The point is that you don't have to have the value multiple times, if you're just dead set against it.

Ceremonious answered 16/10, 2019 at 13:33 Comment(0)
F
0

I didn't feel the need or desire to add a third party package when it seemed like it should be rather simple to implement. So I created a method to do just that.

private static string ParseSetting(string setting, IConfiguration configuration)
{
  // Incoming: {Configuration:FolderOverrides:RouterPath}\\ProcessRoute
  // Result:   TheRoutersPath\\ProcessRoute
  var result = configuration[setting] ?? string.Empty;

  while (result.Contains('{'))
  {
    var lookup = result.Split('{', StringSplitOptions.RemoveEmptyEntries)
      .Where(x => x.Contains('}'))
      .Select(x => x[..x.IndexOf('}')])
      .FirstOrDefault();

    if (lookup is not null)
    {
      var parsed = configuration[lookup];

      if (parsed is not null)
      {
        var newResult = $"{result[..result.IndexOf('{')]}{parsed}{result[(result.IndexOf('}') + 1)..]}";
        result = newResult;
      }
      else
      {
        // Cannot write to the log file yet as this file is setting it up at this point
        throw new ArgumentOutOfRangeException(message: "Check the appSettings file for a missmatch of '{' and '}' and/or validate that the node between '{' and '}' exists.", null);
      }
    }
  }

  return result;
}

Then all you need to do is wherever you are dealing with your settings, inject the configuration into it and pass the injected configuration object to the method.

In my example below I have created a singleton and have defaults in a constants file. Might be overkill for your scenario.

public ConfigurationSettings(IConfiguration configuration) {
  ...
  Core.IncomingPath = ParseSetting("Configuration:Core:IncomingPath", configuration) ?? Constants.FolderStructure.Core.IncomingPath;
  ...
}

I didn't see the need for ${} so I dropped the $.

I have ensured that the following scenarios do work:

Single {Configuration:FolderOverrides:RouterPath}\\ProcessRoute

Multiple {Configuration:FolderOverrides:RouterPath}\\ProcessRoute\\{SomeOther:Node}

Together {Configuration:FolderOverrides:RouterPath}{SomeOther:Node}

Fokine answered 27/8 at 12:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.