Create a config file in asp .net core

With asp .net core we have another concept of website.

There is not a scripting language with an interpreter, but we have a software that is listening on a port.

This mean that, the code in Program.cs and Startup.cs files will be executed just the fist time, at program launch. In fact, the Startup.cs file contains the Startup class, that built the middleware pipeline and it will be executed at any request.

So, a big problem that we can have with a config file is this: to any request, we need to read it from the disk, and this can be very expansive with an huge number of users.

A first way to fix this is to use AddJsonFile in the Program class when you build the configuration, and to use like explained here.
However, I use another way to do this, because I prefer access data via dot notation.

Lets see the alternative way to use a config file.

If we think about it, a config file has not a big request of space in memory, so we can think to read it only the first time and place it in memory.

{
  "Database":
  {
    "TablePrefix": "myPref_",
    "Host": "domain",
    "Port": "3306",
    "Schema": "myPref_barb",
    "User": "myUser",
    "Password": "myPass"
  },
  "AppSettings":
  {
    "Secret" :  "xxx"
  },
  "Jwt":
  {
    "SecretKey": "xxx"
  },
  "Facebook":
  {
    "ApiSecret": "xxx",
    "Url": "https://graph.facebook.com/v2.8/me?fields=id,first_name,last_name,email&access_token="
  }
}

We’ll use a json file like config file.

For a simple deserialization of our json, we’ll create the classes for it.

public class Database
{
    public string TablePrefix { get; set; }
    public string Host { get; set; }
    public string Port { get; set; }
    public string Schema { get; set; }
    public string User { get; set; }
    public string Password { get; set; }
}
public class Jwt
{
    public string SecretKey { get; set; }
}
public class Facebook
{
    public string ApiSecret { get; set; }
    public string Url { get; set; }
}
public class AppSettings
{
    public string Secret = null;
}
/// <summary>
/// Config
/// </summary>
public class Config
{
    public Database Database { get; set; }
    public Jwt Jwt { get; set; }
    public AppSettings AppSettings { get; set; }
    public Facebook Facebook { get; set; }
}

We can easly get classes from json with this tool.

Now we can deserialize the json directly in our object.

Our target now is to keep in memory the configuration from the first access. This can be done placing a static attribute in a class.

public class GlobalConfig
{
    /// <summary>
    /// Our config object
    /// </summary>
    public static Config Config = null;
}

After that, in our Startup class, in the Configure method (be careful, in the method, NOT in a middleware) we need to read the file.

The file reading is an async operation, but the Configure method isn’t it. A workaround is to create a method that fill our GlobalConfig class.

private async Task ReadConfig(IHostingEnvironment env)
{
    string json = null;
    using (Stream file = env.ContentRootFileProvider.GetFileInfo("config.json").CreateReadStream())
    {
         using (StreamReader streamReader = new StreamReader(file))
         {
              json = await streamReader.ReadToEndAsync();
         }
    }
    GlobalConfig.Config = Newtonsoft.Json.JsonConvert.DeserializeObject<Config>(json);
}

Note: We are using Newtonsoft JSON package to deserialize.

So we can call in Configure method this way:

ReadConfig(env).Wait();

We can now read in our code the config values this way:

System.Diagnostics.Debug.WriteLine(GlobalConfig.Config.Database.Host);

Hope this can help you.