Reading constants from appsettings.json

Introduction

Towards the end of the previous post, 'Deploying to Azure', (and the YouTube video) I speculated that it would be useful to use the fact that we could read different values of the same constant from appsettings.json and appsettings.Development.json depending on whether the app was being run in production or development mode.  In this post we will look at how this can be achieved.

YouTube Video

The example we will use is the 'server address' for viewing an order included in the body of the email sent to the supplier.  So far we have 'hard-coded' this in the code for sending an email in the Index.page.  Whilst we were developing the project we hard-coded this to "https://localhost:nnnn/previeworder/guid".  Once we were ready to publish the app to Azure we had to amend this to "https://blazorpurchaseorders.azurewebsites.net/previeworder/guid", where "blazorpurchaseorders.azurewebsites.net" was the web address of the azure site to which the app was published.

For development and testing, or production, we could simply have had two lines of code, one pointing to loacalhost and the other to the azure website address, and then commented out the appropriate line depending on whether we were about to publish or develop.  The problem with this is that, although it's simple, it depends on the programmer remembering to comment out the line of code at the right time.  Even with one variable this is asking for trouble, with multiple variables this is going to be disastrous. 

The answer to this problem is to record the value for the constant in two places: for production in appsettings.json and for development in appsettings.Development.json.

Reading the constant

We are already reading constants from appsettings.json, for example for the default SQL connection string and email settings.  I was therefore tempted to use these as the basis for a general technique.  However the methods used for both seem to entail separate data model classes and appeared to be more complicated than I hoped.  My goal is therefore a simple technique or pattern that doesn't require separate classes and services.

Luckily, the answer isn't too complex.

Let's start by looking at how the constants are recorded in appsettings.json.  A typical piece of json code will look like this:

The first thing to note is that data can be nested.  This can be useful for keeping similar data together, but is not a requirement.  In the above example I have created a 'top-level' section called "ApplicationSettings" with just a single entry called "PreviewOrderLinkRoute".  There is nothing special about either of these names - they just popped into my head!

In our case we want to be able to vary the web address for the 'Preview Order' link in the email sent to the supplier.  The email to the supplier is handled in the Index page, so that's where we will be making changes to read the constant recorded in appsettings.json.

To read this data we need to do the following:

  • At the top of Index.razor we need to add "@using Microsoft.Extensions.Configuration". 
  • We also need to inject IConfiguration with the code "@inject IConfiguration _config".
    • (Both of these statements are essentially part of the built-in plumbing that allows us to get configuration information from, for example, appsettings.json.)
  • Declare a variable, including the type, for the data we are going to read.
  • Read the data in a suitable method using the format:
    • variable= _config.GetValue<variable type>("TopSection:NextSection:Item");
    • where 'TopSection', 'NextSection' and 'Item' refer to the nested section and item names in appsettings.json. If 'TopSection' and 'NextSection' don't exist they can be omitted. 

In our particular case the code is:

@using Microsoft.Extensions.Configuration
@inject IConfiguration _config
string ServerLocation = "";

We will read the constant for ServerLocation on the page 'OnInitialisedAsync' method.  Insert this code after 'Toolbaritems' code.

ServerLocation = _config.GetValue<string>("ApplicationSettings:PreviewOrderLinkRoute");

With the constant now in the ServerLocation variable, now all that's required is to include that in the emailbody lines that build up the location address:

 emailbody = emailbody + "<p>"+ ServerLocation +"/previeworder/" + selectedPOHeaderGuid + "</p>";

I am having to show the code as an image because &quot; gets converted to " in code!!

appsettings.Development.json

Lastly, for the development environment we need to include the same section in appasettings.Development.json, but with the localhost address, e.g.

"ApplicationSettings": {
    "PreviewOrderLinkRoute": "https://localhost:44377"
  }

There is, of course, no requirement to include a section in appsettings.Development.json if there is no need to have separate constants for production and development.

References

For a more complete discussion on appsettings.json I would recommend this video by Tim Corey. Intro to AppSettings in.NET core