C#
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C#
-
Section 4: Working with Data
-
Section 5: Error Handling
-
Section 6: Delegates and Events
-
Section 7: Async Programming
-
Section 8: More Language Features
-
Section 9: File I/O and Serialization
-
Section 10: Networking in .NET
-
Section 11: The .NET Ecosystem
-
Section 12: Memory and Performance
-
Section 13: Concurrency Beyond Async
-
Section 14: Reflection and Attributes
-
Section 15: Testing and Best Practices
-
Section 16: Design Patterns in C#
-
Section 17: Standard Library Deep Dive
-
Section 18: Data Structures and Algorithms in C#
-
Section 19: GUI and Desktop Development Overview
-
Section 20: Practical Projects
-
Section 21: More Practice Exercises
-
Section 22: More Standard Library and Text Processing
-
Section 23: More Design Patterns
-
Section 24: More Projects
-
Section 25: Interview Practice
-
Section 26: C# Keywords Reference (Modifiers)
-
Section 27: C# Keywords Reference (Statements)
-
Section 28: C# Keywords Reference (Operators)
-
Section 29: BCL: System.Collections.Generic
-
Section 30: BCL: System.Linq
-
Section 31: BCL: System.Threading
-
Section 32: BCL: System.IO
-
Section 33: BCL: System.Text and System.Text.Json
-
Section 34: BCL: System.Net.Http
-
Section 35: C# Language Specification Topics
-
Section 36: More Practice Exercises
-
Section 37: More Async Patterns
-
Section 38: More BCL: System.Reflection and System.Diagnostics
-
Section 39: Nullable Reference Types In Depth
-
Section 40: C# Records and Pattern Matching In Depth
-
Section 41: Dependency Injection Deep Dive
-
Section 42: More Interview and Whiteboard Practice
118: Working with Environment Variables and Configuration
I've seen it happen a dozen times: a junior developer pushes a project to GitHub, and within ten minutes, they get an email from a security bot telling them their AWS secret key or SendGrid API token has been leaked. It's a rite of passage, but it's one we can easily avoid. The root of the problem is usually the same—treating configuration as part of the code rather than as part of the environment.
The Hardcoded Trap and the Git Leak
When you're first hacking together a prototype, it's tempting to just drop your API key right into a string. It's fast, and it works. You might write something like this:
public class WeatherService
{
private const string ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; // Quick and easy, right?
public async Task GetForecast()
{
var client = new HttpClient();
var response = await client.GetAsync($"https://api.weather.com/v3/forecast?key={ApiKey}");
// ...
}
}
Here is where it breaks. First, if you need to change that key—say, switching from a sandbox account to a production account—you have to recompile and redeploy the entire application. Second, and more importantly, that key is now forever etched into your version control history. Even if you delete the line in a later commit, the key is still there in the Git history for anyone to find. You've essentially handed the keys to your house to anyone who can see your repository.
Moving to Config Files, but Not Solving Everything
The next step most developers take is moving those strings into an appsettings.json file. This is better because it separates the "what" from the "how." You're using the .NET IConfiguration system, which is the gold standard for C# apps.
// appsettings.json
{
"WeatherApi": {
"ApiKey": "sk_test_4eC39HqLyjWDarjtT1zdp7dc",
"BaseUrl": "https://api.weather.com/v3/"
}
}
In your code, you'd inject IConfiguration and pull the value out: _config["WeatherApi:ApiKey"]. This feels professional, and it allows you to have different files for different environments (like appsettings.Development.json). But we still have a problem: someone is eventually going to forget to add appsettings.json to the .gitignore file, and we're right back to the "Git Leak" nightmare.
Decoupling Secrets via Environment Variables
The real "pro" move is to treat appsettings.json as a place for non-sensitive defaults (like the API Base URL) and use Environment Variables for the actual secrets. Environment variables live on the machine running the code, not in the code itself. This means your production server has the real key, your local machine has a test key, and neither is ever committed to Git.
The beauty of .NET is that the ConfigurationBuilder can stack these sources. It reads the JSON file first, and then it reads the environment variables. If a variable exists in both places, the environment variable wins. I always set it up this way because it gives me the best of both worlds: a readable config file for structure, and secure overrides for secrets.
// In your Program.cs or Host setup
var builder = Host.CreateApplicationBuilder(args);
// .NET does this by default in most templates, but here is the logic:
builder.Configuration
.AddJsonFile("appsettings.json", optional: true)
.AddEnvironmentVariables();
var apiKey = builder.Configuration["WeatherApi:ApiKey"];
// This will check appsettings.json, but if an environment variable
// named 'WeatherApi__ApiKey' exists, it will use that instead.
Notice the double underscore (__) in the environment variable name. That's a C# convention; since many operating systems don't like colons in variable names, .NET maps double underscores to the configuration hierarchy. If you're on Windows, you can set this in your system settings; on Linux, you'd add it to your .bashrc or your Docker Compose file. Your code remains agnostic to where the value comes from—it just knows it needs a key to make the API call work.
📋 Practical Task
Exercise: Securing a Third-Party API Integration for a Weather Dashboard
You have been handed a small console application that fetches weather data. Currently, the API key is hardcoded into a static class, and the application is failing to run in the production environment because the production key is different from the development key.
Your Goal: Refactor the application to remove the hardcoded secret and implement a layered configuration approach.
- Step 1: Create an
appsettings.jsonfile. Move theBaseUrl(e.g.,https://api.weatherapi.com/v1) into this file. - Step 2: Remove the hardcoded
ApiKeystring from the C# code entirely. - Step 3: Update the
Program.csto useConfigurationBuilderto load both the JSON file and the Environment Variables. - Step 4: Modify the service to retrieve the
ApiKeyviaIConfiguration. - Step 5: Test your implementation by setting a local environment variable named
WeatherSettings__ApiKeyon your machine and verifying that the application reads this value instead of any value found in the JSON file.
There are no comments for now.