12

In my .NET Core application, I added an array to the appsettings.json, which looks like this:

{
  "SettingsA": {
    "PropA": [
        "ChildObjectA": {
          ...
        },
        "ChildObjectB": {
          ...
        }
    ]
  }
}

If I would like to override that value from Application Settings in my azure app service, so that it will have empty array:

{
  "SettingsA": {
    "PropA": []
  }
}

Is there a way to do this?

I tried to put

SettingsA:PropsA  ->  []

In the application settings, but it doesn't seem to override the value of appsettings.json

7 Answers 7

15

Just to top up all the great answers already given here, here is how we did it in our real life scenario.

We needed a collection of supported languages to be configured in our app settings. Here is how it looked in the appSettings.json in our .NET Core project:

{
    ...

    "SupportedLanguages": [
        {
            "Code": "en-AU",
            "Name": "English (Australia)"
        },
        {
            "Code": "en-GB",
            "Name": "English (United Kingdom)"
        },
        {
            "Code": "en-US",
            "Name": "English (United States)"
        }
    ]
}

And this is how it ended up looking in our Azure App Service:

enter image description here

It's a bit fiddly, especially if you have a larger or more complex hierarchy, but I don't think there's another way for now.

Sign up to request clarification or add additional context in comments.

Comments

14

The answer here https://www.ryansouthgate.com/2016/03/23/iconfiguration-in-netcore/ is that you can override elements within an array or add additional elements but he says that you can't override the entire array, which seems strange.

Syntax for overriding uses zero-based access such as SettingsA:PropA:0:Something and I have tried this on App Services and can confirm it works.

2 Comments

This is the only relevant answer and it is correct. The short answer is the following syntax in Application settings: ArrayName:Index Value. From the question: SettingsA:PropA:0:ChildObjectA value
On a linux app service, use __ instead of :
3

To to this using a multiplataform syntax on Azure use __

This way works for both Windows and Linux deployed App Services:

SettingsA__PropA__0__Something

Comments

2

You could use AddEnvironmentVariables property to achieve override appsettings on azure to local settings.

First configure the setting in portal: enter image description here

Note: The value here is null.

To override nested keys in the App Settings section we can define a variable using the full path SettingsA:PropA as name or using double underscore SettingsA__PropA. You could refer to this article.

In local, you could configure as below: In 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 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();
            services.AddOptions();
            services.Configure<SettingsOptions>(configuration.GetSection("SettingsA"));

        }

In appsettings.json:

{"SettingsA": {
    "PropA": ["a","b"]
    }
}

In HomeController:

private readonly IOptions<SettingsOptions> options;
        public HomeController(IOptions<SettingsOptions> options)
        {
            this.options = options;
        }

        public IActionResult Index()
        {
            var value = options.Value;
            ViewBag.Index = value.PropA+"success";
            return View();
        }

In SettingsOption:

public class SettingsOptions
    {
        public string SettingsA { get; set; }
        public string PropA { get; set; }
    }

After you publish the project to azure, it will override the PropA value. For more details about how to read appsetting from asp.net core, please follow this case.

1 Comment

This doesn't answer the question at all. The question was specifically about arrays.
0

This is very strange behaviour by microsoft team. Looks like they are not aware of how the reality looks like.

I ended up with having a string with comma separated values instead of arrays.

Comments

0

(This answer is a supplemental to @Lukos' and @KenR's answers.)

I had a similar scenario to the OP where I needed to override values or empty an array in the app settings of a web App Service in the Azure portal. To avoid the manual entry process, I generated JavaScript to automate the process of converting JSON used in appsettings.json to the JSON format used in the bulk edit/import in the Azure portal. The bulk edit/import JSON format is listed here and here.

enter image description here

enter image description here

The HTML/CSS/JavaScript snippet below includes a check box to empty all values in an array and a text input control to set the separator character (e.g. __ double underscore or : colon).

document.addEventListener("DOMContentLoaded", initialize);

let sourceEl,
  resultEl,
  separatorEl,
  emptyArrEl;

let resultArr,
  sep,
  setValToEmpty;

function initialize() {
  sourceEl = document.querySelector("#source-str");
  resultEl = document.querySelector("#result");
  separatorEl = document.querySelector("#separator-input");
  emptyArrEl = document.querySelector("#empty-arr-input");
  document.querySelector("#convert-src").addEventListener("click", convertClick);
}

function convertClick() {
  const sourceStr = sourceEl.value;
  const sepChar = separatorEl.value;
  const emptyArr = emptyArrEl.checked;
  const convertResult = convert(sourceStr, sepChar, emptyArr);
  if (!Array.isArray(convertResult)) {
    console.error(convertResult);
    return;
  }
  const json = JSON.stringify(resultArr, undefined, 2);
  resultEl.textContent = json;
  //resultEl.scrollIntoView({ behavior: "smooth" });
}

function convert(sourceStr, sepChar, emptyArr) {
  if (!sourceStr) {
    return {
      message: "An appsettings.json array string was not entered into the text area"
    };
  }

  // Remove whitespace from both ends of the source string
  sourceStr = sourceStr.trim();

  // Add an open curly bracket ('{') if this character
  // is not at the beginning of the trimmed string.
  // Assume a close curly bracket does not exist
  // if an opening curly bracket does not exist.
  if (sourceStr.indexOf("{") !== 0) {
    sourceStr = "{" + sourceStr + "}";
  }

  // Convert the source string into an object using
  // 'JSON.parse()' within a 'try...catch' statement.

  let srcObj;

  try {
    srcObj = JSON.parse(sourceStr);
  } catch (error) {
    return error;
  }

  resultArr = [];

  // If the separator input control returns an empty value,
  // then default to a double underscore ("__")
  // (a multiplataform syntax on Azure App Service).
  sep = !sepChar ? "__" : sepChar;

  setValToEmpty = emptyArr;

  parseObj(srcObj, "");

  return resultArr;
}

// Use template literals with backticks (`${value}`)
// to convert non-strings (e.g. boolean, numbers) to string.

function parseObj(obj) {
  // Set the 'arrName' variable to the key
  for (let [arrName, value] of Object.entries(obj)) {

    if (Array.isArray(value)) {
      iterateNamedArray(arrName, value);
    }
  }
}

function iterateNamedArray(arrName, value) {
  for (let i = 0; i < value.length; i++) {
    if (typeof value[i] === "object") { // Array of objects
      if (setValToEmpty) {
        const name = `${arrName}${sep}${i}`;
        resultArr.push({
          name: name,
          value: ""
        });
        continue;
      }
      // Iterate entries of 'value[i]' object
      for (let [propName, propValue] of Object.entries(value[i])) {
        const name = `${arrName}${sep}${i}${sep}${propName}`;
        resultArr.push({
          name: name,
          value: `${propValue}`
        });
      }
    } else { // Array of strings, integers, booleans
      const name = `${arrName}${sep}${i}`;
      if (setValToEmpty) {
        value[i] = "";
      }
      resultArr.push({
        name: name,
        value: `${value[i]}`
      });
    }
  }
}
body {
  display: grid;
  grid-gap: 0.5rem;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

h4 {
  margin: 0;
  padding: 0
}

#source-str {
  width: 80%;
  height: 10rem;
  padding: 0.5rem 1rem;
  border: 1px solid #ddd;
  font-size: 0.95rem;
  white-space: pre;
  margin-bottom: 1rem;
}

#result {
  background: #f7f7f7;
  border: 1px solid #ddd;
  border-left: 3px solid #1c8dc3;
  margin: 0;
  padding: 0.5rem 1rem;
  box-sizing: border-box;
  font-size: 1rem;
  line-height: 1.6;
  width: 90%;
  min-height: 15rem;
  white-space: pre-wrap;
}

#controls {
  display: flex;
  flex-direction: row;
  gap: 2rem;
  align-items: center;
  align-content: center;
  margin-bottom: 1rem;
}

#convert-src {
  background-color: #1c8dc3;
  color: #fff;
  padding: 0.5rem;
  border: unset;
  width: fit-content;
}

label {
  display: grid;
  grid-auto-flow: column;
  justify-content: start;
  grid-gap: .5rem;
  align-items: center;
}

#separator-input {
  width: 2rem;
  height: 1.5rem;
  text-align: center;
  font-weight: bold;
  display: grid;
  border: 1px solid #ddd;
}

#empty-arr-input {
  width: 1.2rem;
  height: 1.2rem;
}
<!DOCTYPE html>
<html lang='en'>

<head>
  <meta charset='utf-8' />
  <title>Convert appsettings.json to Azure bulk import - Simple</title>
  <link href="~/css/convert-appsettings-simple.css" rel="stylesheet" />
</head>

<body>
  <h4>appsettings.json</h4>
  <textarea id="source-str" title="appsettings JSON text">
"SupportedLanguages": [
  {
    "Code": "en-AU",
    "Name": "English (Australia)"
  },
  {
    "Code": "en-GB",
    "Name": "English (United Kingdom)"
  },
  {
    "Code": "en-US",
    "Name": "English (United States)"
  }
],
"Unsupported": [
  {
    "Code": "fr-FR",
    "Name": "French (France)"
  },
  {
    "Code": "fr-CA",
    "Name": "French (Canada)"
  }
],
"SpellCheckers": [
    "UKEng.dll",
    "AusEng.dll"
]
    </textarea>
  <div id="controls">
    <label>
            <span>Separator</span>
            <input type="text" id="separator-input" value="__" />
        </label>
    <label>
            <span>Empty array</span>
            <input type="checkbox" id="empty-arr-input" />
        </label>
    <button type="button" id="convert-src">Convert</button>
  </div>
  <h4>Azure bulk edit JSON</h4>
  <pre id="result"></pre>
  <script type="module" src="~/js/convert-appsettings-simple.js"></script>
</body>

</html>

Comments

-1

As far as I know, the settings in the Application settings are injected into your appsettings.json at runtime, overriding existing settings. It will not change the appsettings.json file, because Azure GUI (Connection trings, Application settings) uses environment variables internally.

Here is a similar post for you to refer. You could override the settings during release via VSTS. Here are the links to Colin's ALM Corner Build & Release Tools and tutorial. For more details, you could refer to psycho's reply in the above post.

If there is a need for an appsettings.json's value to be overwritten during VSTS release activity (before it will be published to Azure), Colin's ALM Corner Build & Release Tools can be used.

2 Comments

Thanks for clarifying. That's what I meant. I meant override not replace
This is not true for webjobs

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.