ASP.NET Core learning notes Part 4 configuration in ASP.NET Core

preface

I've been a little busy recently and I'm a little lazy in my study (ashamed). I take time to learn and finish this blog. I hope to understand. I believe I can stick to it and finish this series. All right, let's do it. When it comes to configuration files, most software will involve configuration files for scalability and flexibility, such as app.config and web.config. Then say. NET Core, many have changed. Generally speaking, technology is progressing, new methods are more lightweight, have better scalability, and data sources are more diverse.

Configuration providers available for ASP.NET Core applications

Provider The following objects provide configuration
Azure Key Vault configuration provider Azure Key Vault
Azure application configuration provider Azure application configuration
Command line configuration provider Command line parameters
Custom configuration provider Custom source
Environment variable configuration provider environment variable
Profile provider INI, JSON, and XML files
Key per file configuration provider Catalog file
Memory configuration provider In memory collection
User confidentiality Files in the user profile directory

The typical order of configuring providers is:
1.appsettings.json
2.appsettings.Environment.json
3. User confidentiality
4. Use the environment variable configuration provider to provide through the environment variable.
5. Use the command line configuration provider to provide through command line parameters.
Note: it is common practice to add a command line configuration provider to the end of a series of providers so that command line parameters can override the configuration set by other providers.

Three elements of configuration model

The configuration system of. NET Core consists of three core objects: IConfiguration, IConfigurationBuilder and IConfigurationSource.

  • IConfiguration: the read configuration information will eventually be converted into an IConfiguration object for use by the application.
  • IConfigurationBuilder: IConfigurationBuilder is the builder of IConfiguration objects.
  • IConfigurationSource: represents the most original source of configuration data.

File configuration

Read INI file configuration

First, create an ASP. Net core web API project and add the MyIniConfig.ini file in the home directory.

ID=1
Title="INIConfig title"
Name="INIConfig name"

[Logging:LogLevel]
Default=Information

Read the configuration file in the Program class

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.Sources.Clear();

                var env = hostingContext.HostingEnvironment;

                config.AddIniFile("MyIniConfig.ini", optional: true, reloadOnChange: true);              config.AddEnvironmentVariables();

                if (args != null)
                {
                    config.AddCommandLine(args);
                }
            })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }

Create a new controller named SettingsController and read the configuration file.

    [Route("api/[controller]/[action]")]
    [ApiController]
    public class SettingsController : ControllerBase
    {
        private readonly IConfiguration Configuration;
        public SettingsController(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        public ContentResult INISetting()
        {
            int id = Configuration.GetValue<int>("ID");
            var title = Configuration["Title"];
            var defaultLogLevel = Configuration["Logging:LogLevel:Default"];
            return Content($"ID:{id}\n" +$"Title:{title}\n"+
                $"Default Log Level: {defaultLogLevel}");
        }
    }

Using PostMan, you can see that the INI file just set has been read.

Read the Json configuration file.

Create a new ASP.NET Core Web API project and add the MyJsonConfig.json file in the home directory.

{
  "ID": "1",
  "Title": "My JsonConfig",
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    }
  }
}

Read the configuration file in the Program class

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.Sources.Clear();

                var env = hostingContext.HostingEnvironment;
                              config.AddJsonFile("MyJsonConfig.json", optional: true, reloadOnChange: true);
               config.AddEnvironmentVariables();

                if (args != null)
                {
                    config.AddCommandLine(args);
                }
            })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }

Create a new controller named SettingsController and read the configuration file.

    [Route("api/[controller]/[action]")]
    [ApiController]
    public class SettingsController : ControllerBase
    {
        private readonly IConfiguration Configuration;
        public SettingsController(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        public ContentResult JsonSetting()
        {
            int id = Configuration.GetValue<int>("ID");
            var title = Configuration["Title"];
            var defaultLogLevel = Configuration["Logging:LogLevel:Default"];

            return Content($"ID:{id}\n" + $"Title:{title}\n" +
                $"Default Log Level: {defaultLogLevel}");
        }
    }

Using PostMan, you can see that the Json file just set has been read.

Read XML file

Create a new ASP.NET Core Web API project and add MyXMLConfig.xml file in the home directory.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <ID>1</ID>
  <Title>MyXMLConfig Title</Title>
  <Name>MyXMLConfig Name</Name>
  <Logging>
    <LogLevel>
      <Default>Information</Default>
    </LogLevel>
  </Logging>
</configuration>

Read the configuration file in the Program class

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
               config.Sources.Clear();
               var env = hostingContext.HostingEnvironment;
               config.AddXmlFile("MyXMLConfig.xml", optional: true, reloadOnChange: true);
               config.AddEnvironmentVariables();

                if (args != null)
                {
                    config.AddCommandLine(args);
                }
            })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }

Create a new controller named SettingsController and read the configuration file.

    [Route("api/[controller]/[action]")]
    [ApiController]
    public class SettingsController : ControllerBase
    {
        private readonly IConfiguration Configuration;
        public SettingsController(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        public ContentResult XmlSetting()
        {
            int id = Configuration.GetValue<int>("ID");
            var title = Configuration["Title"];
            var defaultLogLevel = Configuration["Logging:LogLevel:Default"];

            return Content($"ID:{id}\n" + $"Title:{title}\n" +
                $"Default Log Level: {defaultLogLevel}");
        }
    }

Using PostMan, you can see the configuration of the XML file that has been read.

Method of reading configuration item

Here are some common methods for reading configuration items. You can try them yourself according to the above examples. I won't explain them in detail here.

GetValue

ConfigurationBinder.GetValue extracts a value with the specified key from the configuration and converts it to the specified type. In the above, int id = Configuration.GetValue("ID"); This method is used to obtain the specified type.

GetSection

IConfiguration.GetSection returns the configuration sub section with the specified sub section key.

GetChildren

The IConfiguration.GetChildren method obtains the direct descendant configuration sub section.

Exists

ConfigurationExtensions.Exists(IConfigurationSection) determines whether the section has a Value or child.

Bind configuration to object

Create a new ASP.NET Core Web API project and add the MyArray.json file in the home directory.

{
  "array": {
    "entries": {
      "0": "value0",
      "1": "value1",
      "2": "value2",
      "3": "value3"
    }
  }
}

Create a model.

    public class Model
    {
        public string[] Entries { get; set; }
    }

Read the configuration file in the Program class

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
               config.Sources.Clear();
               var env = hostingContext.HostingEnvironment;
               config.AddJsonFile("MyArray.json",optional: true,reloadOnChange: true);
               config.AddEnvironmentVariables();

                if (args != null)
                {
                    config.AddCommandLine(args);
                }
            })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }

Create a new controller named SettingsController and read the configuration file.

    [Route("api/[controller]/[action]")]
    [ApiController]
    public class SettingsController : ControllerBase
    {
        private readonly IConfiguration Configuration;
        public SettingsController(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        public ContentResult ToModel()
        {
        array = Configuration.GetSection("array").Get<Model>();
            string modelStr = null;
            for (int j = 0; j < array.Entries.Length; j++)
            {
                modelStr += $"Index: {j}  Value:  {array.Entries[j]} \n";
            }

            return Content(modelStr);
        }
    }

Using PostMan, you can see that the configuration bound to the Model has been read.

Custom configuration

If the above method can not meet the project requirements, you can also read the configuration information from the database. Next, we read the configuration information in the database through the Entity Framework (EF). For ease of operation, the memory database is used as the configuration source this time.
First, create an entity.

    public class EFModel
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string Value { get; set; }
    }

Add EFConfigContext to store and access configured values.

    public class EFConfigContext:DbContext
    {
        public EFConfigContext(DbContextOptions options) : base(options)
        {
        }

        public DbSet<EFModel> Values { get; set; }
    }

Create a class that implements IConfigurationSource.

    public class EFConfigurationSource : IConfigurationSource
    {
        private readonly Action<DbContextOptionsBuilder> _optionsAction;

        public EFConfigurationSource(Action<DbContextOptionsBuilder> optionsAction)
        {
            _optionsAction = optionsAction;
        }

        public IConfigurationProvider Build(IConfigurationBuilder builder)
        {
            return new EFConfigurationProvider(_optionsAction);
        }
    }

Create a custom configuration provider by inheriting from the ConfigurationProvider. When the database is empty, the configuration provider initializes it.

    public class EFConfigurationProvider:ConfigurationProvider
    {
        Action<DbContextOptionsBuilder> OptionsAction { get; }
        public EFConfigurationProvider(Action<DbContextOptionsBuilder> optionsAction)
        {
            OptionsAction = optionsAction;
        }

        public override void Load()
        {
            var builder = new DbContextOptionsBuilder<EFConfigContext>();

            OptionsAction(builder);

            using (var dbContext =new EFConfigContext(builder.Options))
            {
                dbContext.Database.EnsureCreated();

                Data =!dbContext.Values.Any()?CreateAndSaveValues(dbContext) : dbContext.Values.ToDictionary(c => c.Name, c => c.Value);
            }

        }

        private static IDictionary<string, string> CreateAndSaveValues(EFConfigContext dbContext)
        {
            var configValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
            {
                {"name1","value1" },
                {"name2","value2" },
                {"name3","value3" }
            };

            dbContext.Values.AddRange(configValues.Select(v => new EFModel
            {
                Name = v.Key,
                Value = v.Value
            }).ToArray());

            dbContext.SaveChanges();

            return configValues;
        }
    }

Use the AddEFConfiguration extension method to add a configuration source to ConfigurationBuilder.

    public static class EFExtensions
    {
        public static IConfigurationBuilder AddEFConfiguration(this IConfigurationBuilder builder,Action<DbContextOptionsBuilder> optionsAction)
        {
            return builder.Add(new EFConfigurationSource(optionsAction));
        }
    }

Use the custom EFConfigurationProvider in Program.cs:

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.Sources.Clear();

                var env = hostingContext.HostingEnvironment;

                config.AddEFConfiguration(
                options => options.UseInMemoryDatabase("InMemoryDb"));
       

                config.AddEnvironmentVariables();

                if (args != null)
                {
                    config.AddCommandLine(args);
                }
            })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }

In Startup, a database context service is added through dependency injection to provide services to the controller.

    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<EFConfigContext>(opt => opt.UseInMemoryDatabase("InMemoryDb"));
            services.AddControllers();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }

Inject services into the controller to read the data in the memory database.

    [Route("api/[controller]/[action]")]
    [ApiController]
    public class SettingsController : ControllerBase
    {

        private readonly EFConfigContext _efDbContext;

        public SettingsController( EFConfigContext efDbContext)
        {
            _efDbContext = efDbContext;
        }


        public ActionResult<IEnumerable<EFModel>> EFSetting()
        {
            List<EFModel> list = _efDbContext.Values.ToList();

            return list;
        }
    }

Using PostMan, you can see that our customized configuration source has been read.

Add an overall project structure for everyone to understand.

The epidemic situation has been repeated recently. Do a good job in personal protection when you go out and don't forget to learn when you play. Finally, I wish you a happy weekend!

Tags: ASP.NET

Posted on Fri, 29 Oct 2021 09:14:00 -0400 by derrick24