--- title: Options pattern in ASP.NET Core author: guardrex description: Discover how to use the options pattern to represent groups of related settings in ASP.NET Core apps. ms.author: riande ms.custom: mvc ms.date: 12/29/2018 uid: fundamentals/configuration/options --- # Options pattern in ASP.NET Core By [Luke Latham](https://github.com/guardrex) ::: moniker range="<= aspnetcore-1.1" For the 1.1 version of this topic, download [Options pattern in ASP.NET Core (version 1.1, PDF)](https://webpifeed.blob.core.windows.net/webpifeed/Partners/Options_1.1.pdf). ::: moniker-end The options pattern uses classes to represent groups of related settings. When [configuration settings](xref:fundamentals/configuration/index) are isolated by scenario into separate classes, the app adheres to two important software engineering principles: * The [Interface Segregation Principle (ISP) or Encapsulation](/dotnet/standard/modern-web-apps-azure-architecture/architectural-principles#encapsulation) – Scenarios (classes) that depend on configuration settings depend only on the configuration settings that they use. * [Separation of Concerns](/dotnet/standard/modern-web-apps-azure-architecture/architectural-principles#separation-of-concerns) – Settings for different parts of the app aren't dependent or coupled to one another. Options also provide a mechanism to validate configuration data. For more information, see the [Options validation](#options-validation) section. [View or download sample code](https://github.com/aspnet/Docs/tree/master/aspnetcore/fundamentals/configuration/options/samples) ([how to download](xref:index#how-to-download-a-sample)) ## Prerequisites Reference the [Microsoft.AspNetCore.App metapackage](xref:fundamentals/metapackage-app) or add a package reference to the [Microsoft.Extensions.Options.ConfigurationExtensions](https://www.nuget.org/packages/Microsoft.Extensions.Options.ConfigurationExtensions/) package. ## Options interfaces is used to retrieve options and manage options notifications for `TOptions` instances. supports the following scenarios: * Change notifications * [Named options](#named-options-support-with-iconfigurenamedoptions) * [Reloadable configuration](#reload-configuration-data-with-ioptionssnapshot) * Selective options invalidation () [Post-configuration](#options-post-configuration) scenarios allow you to set or change options after all configuration occurs. is responsible for creating new options instances. It has a single method. The default implementation takes all registered and and runs all the configurations first, followed by the post-configuration. It distinguishes between and and only calls the appropriate interface. is used by to cache `TOptions` instances. The invalidates options instances in the monitor so that the value is recomputed (). Values can be manually introduced with . The method is used when all named instances should be recreated on demand. is useful in scenarios where options should be recomputed on every request. For more information, see the [Reload configuration data with IOptionsSnapshot](#reload-configuration-data-with-ioptionssnapshot) section. can be used to support options. However, doesn't support the preceding scenarios of . You may continue to use in existing frameworks and libraries that already use the interface and don't require the scenarios provided by . ## General options configuration General options configuration is demonstrated as Example #1 in the sample app. An options class must be non-abstract with a public parameterless constructor. The following class, `MyOptions`, has two properties, `Option1` and `Option2`. Setting default values is optional, but the class constructor in the following example sets the default value of `Option1`. `Option2` has a default value set by initializing the property directly (*Models/MyOptions.cs*): [!code-csharp[](options/samples/2.x/OptionsSample/Models/MyOptions.cs?name=snippet1)] The `MyOptions` class is added to the service container with and bound to configuration: [!code-csharp[](options/samples/2.x/OptionsSample/Startup.cs?name=snippet_Example1)] The following page model uses [constructor dependency injection](xref:mvc/controllers/dependency-injection) with to access the settings (*Pages/Index.cshtml.cs*): [!code-csharp[](options/samples/2.x/OptionsSample/Pages/Index.cshtml.cs?range=9)] [!code-csharp[](options/samples/2.x/OptionsSample/Pages/Index.cshtml.cs?name=snippet2&highlight=2,8)] [!code-csharp[](options/samples/2.x/OptionsSample/Pages/Index.cshtml.cs?name=snippet_Example1)] The sample's *appsettings.json* file specifies values for `option1` and `option2`: [!code-json[](options/samples/2.x/OptionsSample/appsettings.json?highlight=2-3)] When the app is run, the page model's `OnGet` method returns a string showing the option class values: ```html option1 = value1_from_json, option2 = -1 ``` > [!NOTE] > When using a custom to load options configuration from a settings file, confirm that the base path is set correctly: > > ```csharp > var configBuilder = new ConfigurationBuilder() > .SetBasePath(Directory.GetCurrentDirectory()) > .AddJsonFile("appsettings.json", optional: true); > var config = configBuilder.Build(); > > services.Configure(config); > ``` > > Explicitly setting the base path isn't required when loading options configuration from the settings file via . ## Configure simple options with a delegate Configuring simple options with a delegate is demonstrated as Example #2 in the sample app. Use a delegate to set options values. The sample app uses the `MyOptionsWithDelegateConfig` class (*Models/MyOptionsWithDelegateConfig.cs*): [!code-csharp[](options/samples/2.x/OptionsSample/Models/MyOptionsWithDelegateConfig.cs?name=snippet1)] In the following code, a second service is added to the service container. It uses a delegate to configure the binding with `MyOptionsWithDelegateConfig`: [!code-csharp[](options/samples/2.x/OptionsSample/Startup.cs?name=snippet_Example2)] *Index.cshtml.cs*: [!code-csharp[](options/samples/2.x/OptionsSample/Pages/Index.cshtml.cs?range=10)] [!code-csharp[](options/samples/2.x/OptionsSample/Pages/Index.cshtml.cs?name=snippet2&highlight=3,9)] [!code-csharp[](options/samples/2.x/OptionsSample/Pages/Index.cshtml.cs?name=snippet_Example2)] You can add multiple configuration providers. Configuration providers are available from NuGet packages and are applied in the order that they're registered. For more information, see . Each call to adds an service to the service container. In the preceding example, the values of `Option1` and `Option2` are both specified in *appsettings.json*, but the values of `Option1` and `Option2` are overridden by the configured delegate. When more than one configuration service is enabled, the last configuration source specified *wins* and sets the configuration value. When the app is run, the page model's `OnGet` method returns a string showing the option class values: ```html delegate_option1 = value1_configured_by_delgate, delegate_option2 = 500 ``` ## Suboptions configuration Suboptions configuration is demonstrated as Example #3 in the sample app. Apps should create options classes that pertain to specific scenario groups (classes) in the app. Parts of the app that require configuration values should only have access to the configuration values that they use. When binding options to configuration, each property in the options type is bound to a configuration key of the form `property[:sub-property:]`. For example, the `MyOptions.Option1` property is bound to the key `Option1`, which is read from the `option1` property in *appsettings.json*. In the following code, a third service is added to the service container. It binds `MySubOptions` to the section `subsection` of the *appsettings.json* file: [!code-csharp[](options/samples/2.x/OptionsSample/Startup.cs?name=snippet_Example3)] The `GetSection` extension method requires the [Microsoft.Extensions.Options.ConfigurationExtensions](https://www.nuget.org/packages/Microsoft.Extensions.Options.ConfigurationExtensions/) NuGet package. If the app uses the [Microsoft.AspNetCore.App metapackage](xref:fundamentals/metapackage-app) (ASP.NET Core 2.1 or later), the package is automatically included. The sample's *appsettings.json* file defines a `subsection` member with keys for `suboption1` and `suboption2`: [!code-json[](options/samples/2.x/OptionsSample/appsettings.json?highlight=4-7)] The `MySubOptions` class defines properties, `SubOption1` and `SubOption2`, to hold the options values (*Models/MySubOptions.cs*): [!code-csharp[](options/samples/2.x/OptionsSample/Models/MySubOptions.cs?name=snippet1)] The page model's `OnGet` method returns a string with the options values (*Pages/Index.cshtml.cs*): [!code-csharp[](options/samples/2.x/OptionsSample/Pages/Index.cshtml.cs?range=11)] [!code-csharp[](options/samples/2.x/OptionsSample/Pages/Index.cshtml.cs?name=snippet2&highlight=4,10)] [!code-csharp[](options/samples/2.x/OptionsSample/Pages/Index.cshtml.cs?name=snippet_Example3)] When the app is run, the `OnGet` method returns a string showing the suboption class values: ```html subOption1 = subvalue1_from_json, subOption2 = 200 ``` ## Options provided by a view model or with direct view injection Options provided by a view model or with direct view injection is demonstrated as Example #4 in the sample app. Options can be supplied in a view model or by injecting directly into a view (*Pages/Index.cshtml.cs*): [!code-csharp[](options/samples/2.x/OptionsSample/Pages/Index.cshtml.cs?range=9)] [!code-csharp[](options/samples/2.x/OptionsSample/Pages/Index.cshtml.cs?name=snippet2&highlight=2,8)] [!code-csharp[](options/samples/2.x/OptionsSample/Pages/Index.cshtml.cs?name=snippet_Example4)] The sample app shows how to inject `IOptionsMonitor` with an `@inject` directive: [!code-cshtml[](options/samples/2.x/OptionsSample/Pages/Index.cshtml?range=1-10&highlight=4)] When the app is run, the options values are shown in the rendered page: ![Options values Option1: value1_from_json and Option2: -1 are loaded from the model and by injection into the view.](options/_static/view.png) ## Reload configuration data with IOptionsSnapshot Reloading configuration data with is demonstrated in Example #5 in the sample app. supports reloading options with minimal processing overhead. Options are computed once per request when accessed and cached for the lifetime of the request. The following example demonstrates how a new is created after *appsettings.json* changes (*Pages/Index.cshtml.cs*). Multiple requests to the server return constant values provided by the *appsettings.json* file until the file is changed and configuration reloads. [!code-csharp[](options/samples/2.x/OptionsSample/Pages/Index.cshtml.cs?range=12)] [!code-csharp[](options/samples/2.x/OptionsSample/Pages/Index.cshtml.cs?name=snippet2&highlight=5,11)] [!code-csharp[](options/samples/2.x/OptionsSample/Pages/Index.cshtml.cs?name=snippet_Example5)] The following image shows the initial `option1` and `option2` values loaded from the *appsettings.json* file: ```html snapshot option1 = value1_from_json, snapshot option2 = -1 ``` Change the values in the *appsettings.json* file to `value1_from_json UPDATED` and `200`. Save the *appsettings.json* file. Refresh the browser to see that the options values are updated: ```html snapshot option1 = value1_from_json UPDATED, snapshot option2 = 200 ``` ## Named options support with IConfigureNamedOptions Named options support with is demonstrated as Example #6 in the sample app. *Named options* support allows the app to distinguish between named options configurations. In the sample app, named options are declared with [OptionsServiceCollectionExtensions.Configure](xref:Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.Configure*), which calls the [ConfigureNamedOptions\.Configure](xref:Microsoft.Extensions.Options.ConfigureNamedOptions`1.Configure*) extension method: [!code-csharp[](options/samples/2.x/OptionsSample/Startup.cs?name=snippet_Example6)] The sample app accesses the named options with (*Pages/Index.cshtml.cs*): [!code-csharp[](options/samples/2.x/OptionsSample/Pages/Index.cshtml.cs?range=13-14)] [!code-csharp[](options/samples/2.x/OptionsSample/Pages/Index.cshtml.cs?name=snippet2&highlight=6,12-13)] [!code-csharp[](options/samples/2.x/OptionsSample/Pages/Index.cshtml.cs?name=snippet_Example6)] Running the sample app, the named options are returned: ```html named_options_1: option1 = value1_from_json, option2 = -1 named_options_2: option1 = named_options_2_value1_from_action, option2 = 5 ``` `named_options_1` values are provided from configuration, which are loaded from the *appsettings.json* file. `named_options_2` values are provided by: * The `named_options_2` delegate in `ConfigureServices` for `Option1`. * The default value for `Option2` provided by the `MyOptions` class. ## Configure all options with the ConfigureAll method Configure all options instances with the method. The following code configures `Option1` for all configuration instances with a common value. Add the following code manually to the `Startup.ConfigureServices` method: ```csharp services.ConfigureAll(myOptions => { myOptions.Option1 = "ConfigureAll replacement value"; }); ``` Running the sample app after adding the code produces the following result: ```html named_options_1: option1 = ConfigureAll replacement value, option2 = -1 named_options_2: option1 = ConfigureAll replacement value, option2 = 5 ``` > [!NOTE] > All options are named instances. Existing instances are treated as targeting the `Options.DefaultName` instance, which is `string.Empty`. also implements . The default implementation of the has logic to use each appropriately. The `null` named option is used to target all of the named instances instead of a specific named instance ( and use this convention). ## OptionsBuilder API is used to configure `TOptions` instances. `OptionsBuilder` streamlines creating named options as it's only a single parameter to the initial `AddOptions(string optionsName)` call instead of appearing in all of the subsequent calls. Options validation and the `ConfigureOptions` overloads that accept service dependencies are only available via `OptionsBuilder`. ```csharp // Options.DefaultName = "" is used. services.AddOptions().Configure(o => o.Property = "default"); services.AddOptions("optionalName") .Configure(o => o.Property = "named"); ``` ## Configure<TOptions, TDep1, ... TDep4> method Using services from DI to configure options by implementing `IConfigure[Named]Options` in a boilerplate manner is verbose. Overloads for `ConfigureOptions` on `OptionsBuilder` allow you to use up to five services to configure options: ```csharp services.AddOptions("optionalName") .Configure( (o, s, s2, s3, s4, s5) => o.Property = DoSomethingWith(s, s2, s3, s4, s5)); ``` The overload registers a transient generic , which has a constructor that accepts the generic service types specified. ::: moniker range=">= aspnetcore-2.2" ## Options validation Options validation allows you to validate options when options are configured. Call `Validate` with a validation method that returns `true` if options are valid and `false` if they aren't valid: ```csharp // Registration services.AddOptions("optionalOptionsName") .Configure(o => { }) // Configure the options .Validate(o => YourValidationShouldReturnTrueIfValid(o), "custom error"); // Consumption var monitor = services.BuildServiceProvider() .GetService>(); try { var options = monitor.Get("optionalOptionsName"); } catch (OptionsValidationException e) { // e.OptionsName returns "optionalOptionsName" // e.OptionsType returns typeof(MyOptions) // e.Failures returns a list of errors, which would contain // "custom error" } ``` The preceding example sets the named options instance to `optionalOptionsName`. The default options instance is `Options.DefaultName`. Validation runs when the options instance is created. Your options instance is guaranteed to pass validation the first time it's accessed. > [!IMPORTANT] > Options validation doesn't guard against options modifications after the options are initially configured and validated. The `Validate` method accepts a `Func`. To fully customize validation, implement `IValidateOptions`, which allows: * Validation of multiple options types: `class ValidateTwo : IValidateOptions, IValidationOptions` * Validation that depends on another option type: `public DependsOnAnotherOptionValidator(IOptionsMonitor options)` `IValidateOptions` validates: * A specific named options instance. * All options when `name` is `null`. Return a `ValidateOptionsResult` from your implementation of the interface: ```csharp public interface IValidateOptions where TOptions : class { ValidateOptionsResult Validate(string name, TOptions options); } ``` Data Annotation-based validation is available from the [Microsoft.Extensions.Options.DataAnnotations](https://www.nuget.org/packages/Microsoft.Extensions.Options.DataAnnotations) package by calling the `ValidateDataAnnotations` method on `OptionsBuilder`. `Microsoft.Extensions.Options.DataAnnotations` is included in the [Microsoft.AspNetCore.App metapackage](xref:fundamentals/metapackage-app) (ASP.NET Core 2.2 or later). ```csharp private class AnnotatedOptions { [Required] public string Required { get; set; } [StringLength(5, ErrorMessage = "Too long.")] public string StringLength { get; set; } [Range(-5, 5, ErrorMessage = "Out of range.")] public int IntRange { get; set; } } [Fact] public void CanValidateDataAnnotations() { var services = new ServiceCollection(); services.AddOptions() .Configure(o => { o.StringLength = "111111"; o.IntRange = 10; o.Custom = "nowhere"; }) .ValidateDataAnnotations(); var sp = services.BuildServiceProvider(); var error = Assert.Throws(() => sp.GetRequiredService>().Value); ValidateFailure(error, Options.DefaultName, 1, "DataAnnotation validation failed for members Required " + "with the error 'The Required field is required.'.", "DataAnnotation validation failed for members StringLength " + "with the error 'Too long.'.", "DataAnnotation validation failed for members IntRange " + "with the error 'Out of range.'."); } ``` Eager validation (fail fast at startup) is under consideration for a future release. ::: moniker-end ## Options post-configuration Set post-configuration with . Post-configuration runs after all configuration occurs: ```csharp services.PostConfigure(myOptions => { myOptions.Option1 = "post_configured_option1_value"; }); ``` is available to post-configure named options: ```csharp services.PostConfigure("named_options_1", myOptions => { myOptions.Option1 = "post_configured_option1_value"; }); ``` Use to post-configure all configuration instances: ```csharp services.PostConfigureAll(myOptions => { myOptions.Option1 = "post_configured_option1_value"; }); ``` ## Accessing options during startup and can be used in `Startup.Configure`, since services are built before the `Configure` method executes. ```csharp public void Configure(IApplicationBuilder app, IOptionsMonitor optionsAccessor) { var option1 = optionsAccessor.CurrentValue.Option1; } ``` Don't use or in `Startup.ConfigureServices`. An inconsistent options state may exist due to the ordering of service registrations. ## Additional resources *