SharpConfig vs. Alternatives: Why Choose SharpConfig for Your .NET Project

Building Robust Apps with SharpConfig: Examples and Pattern Recipes

SharpConfig is a lightweight, flexible configuration library for .NET that offers a clean API for reading, writing, and managing configuration data. This article shows practical examples and design patterns to help you use SharpConfig to build robust, maintainable applications.

Why choose SharpConfig

  • Simple API: Clear types and straightforward read/write methods.
  • Human-friendly format: INI-like structure that’s easy to inspect and edit.
  • Typed access: Retrieve values as strings, ints, booleans, enums, arrays, and more.
  • Programmatic control: Create and modify configs in code; persist to files.

Quick setup

  1. Install via NuGet:

    Code

    Install-Package SharpConfig
  2. Basic load/save pattern:

    csharp

    using SharpConfig; var config = Configuration.LoadFromFile(“app.cfg”); // work with config config.SaveToFile(“app.cfg”);

Core concepts

  • Configuration: Root object containing sections.
  • Section: Named group of settings.
  • Setting: Key-value pair; supports conversion to common types.
  • Comment: Attach human-readable comments to sections or settings.

Example 1 — Application settings (typed access)

Use a dedicated section for app-wide settings and map them to a strongly typed options class.

csharp

public class AppOptions { public string ApiUrl { get; set; } public int MaxRetries { get; set; } public bool EnableCaching { get; set; } } // Load and bind var cfg = Configuration.LoadFromFile(“app.cfg”); var section = cfg[“Application”]; var options = new AppOptions { ApiUrl = section[“ApiUrl”].Value, MaxRetries = section[“MaxRetries”].IntValue, EnableCaching = section[“EnableCaching”].BoolValue };

Pattern tip: wrap this binding in a helper method or extension to centralize defaults and validation.

Example 2 — Environment-specific overrides

Keep base settings and environment sections (Development, Staging, Production). Merge at runtime.

csharp

var cfg = Configuration.LoadFromFile(“config.cfg”); var env = Environment.GetEnvironmentVariable(“APPENV”) ?? “Development”; // Start with base section var baseSec = cfg[“Base”]; var envSec = cfg[env]; // Apply overrides: prefer environment values when present string GetValue(string key) => envSec != null && envSec.Contains(key) ? envSec[key].Value : baseSec[key].Value;

Pattern tip: implement a MergeSections(base, override) utility that copies only present settings.

Example 3 — Plugin/module configs (modularization)

For apps with plugins, load each plugin’s config separately and merge or isolate as needed.

  • Store plugin configs under unique section names (Plugin.[Name]).
  • Provide a PluginConfig class to encapsulate reading/writing for each plugin.

csharp

var cfg = Configuration.LoadFromFile(“plugins.cfg”); var pluginSec = cfg[“Plugin.MyPlugin”]; var enabled = pluginSec[“Enabled”].BoolValue;

Pattern tip: validate plugin config schema on load and fallback to defaults to avoid runtime errors.

Example 4 — Secure/secrets handling

SharpConfig stores plain text. For secrets:

  • Keep sensitive values out of main repo (use environment variables or secret store).
  • Store placeholders in config and resolve at runtime:

csharp

var token = cfg[“Auth”][“Token”].Value; if (token.StartsWith(“env:”)) token = Environment.GetEnvironmentVariable(token.Substring(4));

Pattern tip: implement ResolveSecrets(Configuration) to centralize secret resolution.

Example 5 — Live reload and validation

Support reloading configuration at runtime and validate before applying.

  • Use FileSystemWatcher to monitor config file changes.
  • On change: load into a new Configuration instance, validate, then swap in atomically.

csharp

void OnConfigChanged() { var newCfg = Configuration.LoadFromFile(“app.cfg”); if (Validate(newCfg)) Interlocked.Exchange(ref currentConfig, newCfg); }

Pattern tip: keep a validation layer that returns explicit errors; reject invalid configs to avoid unstable state.

Common recipes

  • Defaults and fallback: Always supply defaults when reading a setting:

    csharp

    int retries = section[“MaxRetries”]?.IntValue ?? 3;
  • Enum parsing: Store enums as strings and parse with Enum.Parse.
  • Lists/arrays: Use comma-separated strings and split/trim when reading.
  • Comments for maintainability: Add comments to explain non-obvious settings.

Error handling and validation

  • Validate required keys and types at startup.
  • Use try/catch around parse operations and log clear messages.
  • Fail fast on critical misconfiguration; for non-critical issues, fall back to safe defaults.

Testing strategies

  • Unit-test config parsing by loading example config snippets from embedded resources.
  • Use integration tests that swap config files and verify behavior under different settings.

Deployment considerations

  • Keep environment-specific config out of source control or encrypted.
  • Document configuration schema and defaults for operators.
  • Automate config checks as part of CI (schema validation, required keys present).

Summary

SharpConfig is well-suited for .NET apps that need readable, programmatic configuration without heavy dependencies. Use typed binding, environment overrides, modular plugin configs, secrets resolution, and live reload with validation to build robust applications. Implement small utility functions (MergeSections, ResolveSecrets, Validate) to centralize behavior and reduce repetition.

If you want, I can generate a sample config file for the examples above or provide helper utilities (MergeSections, Validate, ResolveSecrets) as ready-to-use C# code.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *