Microsoft.Extensions.Configuration has had ConfigurationKeyNameAttribute since .NET 6 which it lets you rename the key a property maps to. But there was never an official way to say "don't bind this property at all." That gap is finally closed in .NET 11 with ConfigurationIgnoreAttribute.
The Problem#
Let's say you have an options class that looks roughly like this:
public class CsvIngestionOptions
{
// Computed after load — should NOT come from configuration
public CsvFormatOptions DefaultFormat { get; set; }
// The raw section we bind and process ourselves
public IConfigurationSection? DefaultFormatSection { get; set; }
internal void OnConfigurationLoaded()
{
DefaultFormat = new CsvFormatOptions();
DefaultFormatSection?.Bind(DefaultFormat);
DefaultFormat.EnsureEncodingDefined();
}
}
DefaultFormat is derived from DefaultFormatSection after some post-processing. It should never be populated directly by the binder. But because it has a public getter and setter, the configuration system happily tries to bind it.
The only workaround before .NET 11 was to abuse ConfigurationKeyNameAttribute with an intentionally garbage key:
// The hacky way
[ConfigurationKeyName("__ignored_" + nameof(DefaultFormat))]
public CsvFormatOptions DefaultFormat { get; set; }
That's fragile, misleading, and creates a weird surface in your configuration schema. Not great.
The Fix: ConfigurationIgnoreAttribute#
.NET 11 adds a dedicated attribute in Microsoft.Extensions.Configuration:
namespace Microsoft.Extensions.Configuration;
[AttributeUsage(AttributeTargets.Property)]
public sealed class ConfigurationIgnoreAttribute : Attribute { }
Easy peasy. Just add the property now to the property in question that should not be bound:
public class CsvIngestionOptions
{
[ConfigurationIgnore]
public CsvFormatOptions DefaultFormat { get; set; }
[ConfigurationKeyName(nameof(DefaultFormat))]
public IConfigurationSection? DefaultFormatSection { get; set; }
internal void OnConfigurationLoaded()
{
DefaultFormat = new CsvFormatOptions();
DefaultFormatSection?.Bind(DefaultFormat);
DefaultFormat.EnsureEncodingDefined();
}
}
Another Common Scenario#
Post-processing is the most obvious use case, but not the only one. A parsed representation of a raw value is another classic:
public class FeatureFlags
{
public string RawFlags { get; set; } = string.Empty;
[ConfigurationIgnore]
public IReadOnlyDictionary<string, bool> ParsedFlags { get; set; }
= new Dictionary<string, bool>();
}
Can't I Just Use [JsonIgnore]?#
Nope and this is the catch. System.Text.Json.Serialization.JsonIgnoreAttribute has no effect on the configuration binder.
GitHub#
The issue is described here: https://github.com/dotnet/runtime/issues/125111