This article provides a comprehensive sample demonstrating how to effectively utilize app settings in ASP.NET Core applications.

Dog

Problem Statement

In the realm of application development, managing settings efficiently can be a pivotal but often overlooked aspect, especially when collaborating with team members. Imagine a scenario where you or your colleagues add or remove settings during development, such as passwords, connection strings, or keys. These sensitive pieces of information should never find their way into your source code control system.

However, a common occurrence is that someone adds a new setting essential for a feature without communicating it to other team members. Consequently, you might encounter unexpected exceptions or peculiar behavior within your application, leading to time-consuming investigations.

Consider this familiar code snippet:

string openAIKey = Environment.GetEnvironmentVariable("OpenAIKey");

This pattern, while prevalent, is both frustrating and risky when employed within teams.

Solution

To mitigate such issues effectively, I strongly advocate for implementing the following practices:

  1. Define Settings in a Dedicated Class
using System.ComponentModel.DataAnnotations;

namespace Oliver.Tools.Copilots
{
    public class OpenAISettings
    {
        public const string Key = "OpenAISettings";

        [Required(ErrorMessage = "OpenAIKey required")]
        public required string OpenAIKey { get; set; }

        [Required(ErrorMessage = "OpenAIEndpoint required")]
        public required string OpenAIEndpoint { get; set; }
    }
}
  1. Configure Settings at Startup in Program.cs
IServiceCollection services = builder.Services;

IConfigurationSection? openAISettings = builder.Configuration.GetSection(OpenAISettings.Key);
services
    .Configure<OpenAISettings>(openAISettings)
    .AddOptionsWithValidateOnStart<OpenAISettings>()
    .ValidateDataAnnotations();
  1. Run the application

Encountering an exception at the application’s start is both beneficial and intentional.

Exception

The sooner the better an exception is thrown, the earlier you can fix a problem. It is getting harder when you need to search late in the development process for a missing setting, somewhere hidden in the some code.

  1. Include Settings in your local appsettings.json File
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "OpenAISettings": {
    "OpenAIKey": "1234567890987654321",
    "OpenAIEndpoint": "https://youropenaiendpoint.openai.azure.com/"
  },
  ...
}

Even though settings are not case-sensitive by default, any minor typos will result in exceptions.

  1. Additional Perk: Dependency Injection

This pattern facilitates effortless dependency injection, allowing settings to be readily injected into other classes.

namespace DataWebApp.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class ChatController : ControllerBase
    {
        private readonly OpenAISettings _mySettings;

        public ChatController(IOptions<OpenAISettings> mySettings)
        {
            _mySettings = mySettings.Value;
        }

        ...        
    }
}

In Conclusion

Adopting this recommended approach not only streamlines your development process but also saves invaluable time that would otherwise be spent scouring through codebases in search of elusive settings.