Megosztás a következőn keresztül:


Beállítások minta a ASP.NET Core-ban

Note

Ez nem a cikk legújabb verziója. Az aktuális kiadásról a cikk .NET 10-es verziójában olvashat.

Warning

A ASP.NET Core ezen verziója már nem támogatott. További információt a .NET és a .NET Core támogatási szabályzatában talál. A jelen cikk .NET 9-es verzióját lásd az aktuális kiadásért .

Rick Andersontól.

Az opciós minta osztályok használatával erősen típusos hozzáférést biztosít a kapcsolódó beállítások csoportjaihoz. Ha a konfigurációs beállításokat forgatókönyvek szerint külön osztályokba különítjük el, az alkalmazás két fontos szoftvermérnöki alapelvnek felel meg:

  • Encapsulation:
    • A konfigurációs beállításoktól függő osztályok csak az általuk használt konfigurációs beállításoktól függnek.
  • Az aggodalmak elkülönítése:
    • Az alkalmazás különböző részeinek beállításai nem függenek egymástól, és nincsenek összekapcsolva.

A beállítások emellett a konfigurációs adatok ellenőrzésére szolgáló mechanizmust is biztosítanak. További információt a Beállítások érvényesítési szakaszában talál.

Ez a cikk a ASP.NET Core beállítási mintájáról nyújt tájékoztatást. A beállítási minta konzolalkalmazásokban való használatáról további információt a .NET Beállítások mintája című témakörben talál.

Hierarchikus konfiguráció kötése

A kapcsolódó konfigurációs értékek olvasásának elsődleges módja a beállítási minta használata. Például a következő konfigurációs értékek olvasásához:

  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  }

Hozza létre a következő PositionOptions osztályt:

public class PositionOptions
{
    public const string Position = "Position";

    public string Title { get; set; } = String.Empty;
    public string Name { get; set; } = String.Empty;
}

Egy beállításosztály:

  • Nem absztraktnak kell lennie.
  • Olyan nyilvános írási-olvasási tulajdonsággal rendelkezik, amelynek megfelelő elemei vannak megkötve a konfigurációban.
  • Olvasási-írási tulajdonságai a konfigurációban lévő bejegyzésekhez vannak kötve.
  • Nem rendelkezik mezői megkötésével. Az előző kódban a Position nincs kötés alatt. A Position mező célja, hogy ne kelljen a "Position" sztringet kézzel kódolni az alkalmazásban, amikor az osztályt egy konfigurációs szolgáltatóhoz kötjük.

A következő kód:

  • A ConfigurationBinder.Bind meghívásával köti az osztályt PositionOptions a Position szakaszhoz.
  • Megjeleníti a Position konfigurációs adatokat.
public class Test22Model : PageModel
{
    private readonly IConfiguration Configuration;

    public Test22Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var positionOptions = new PositionOptions();
        Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

Az előző kódban alapértelmezés szerint a JSON-konfigurációs fájl módosításai az alkalmazás elindítása után jelennek meg.

ConfigurationBinder.Get<T> köti és visszaadja a megadott típust. ConfigurationBinder.Get<T> lehet, hogy kényelmesebb, mint a használata ConfigurationBinder.Bind. Az alábbi kód bemutatja, hogyan használható ConfigurationBinder.Get<T> az PositionOptions osztály:

public class Test21Model : PageModel
{
    private readonly IConfiguration Configuration;
    public PositionOptions? positionOptions { get; private set; }

    public Test21Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {            
        positionOptions = Configuration.GetSection(PositionOptions.Position)
                                                     .Get<PositionOptions>();

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

Az előző kódban alapértelmezés szerint a JSON-konfigurációs fájl módosításai az alkalmazás elindítása után jelennek meg.

A kötés lehetővé teszi egy absztrakt osztály összefűzését is. Vegye figyelembe a következő kódot, amely az absztrakt osztályt SomethingWithANamehasználja:

namespace ConfigSample.Options;

public abstract class SomethingWithAName
{
    public abstract string? Name { get; set; }
}

public class NameTitleOptions(int age) : SomethingWithAName
{
    public const string NameTitle = "NameTitle";

    public override string? Name { get; set; }
    public string Title { get; set; } = string.Empty;

    public int Age { get; set; } = age;
}

A következő kód a NameTitleOptions konfigurációs értékeket jeleníti meg:

public class Test33Model : PageModel
{
    private readonly IConfiguration Configuration;

    public Test33Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var nameTitleOptions = new NameTitleOptions(22);
        Configuration.GetSection(NameTitleOptions.NameTitle).Bind(nameTitleOptions);

        return Content($"Title: {nameTitleOptions.Title} \n" +
                       $"Name: {nameTitleOptions.Name}  \n" +
                       $"Age: {nameTitleOptions.Age}"
                       );
    }
}

A Bind hívások kevésbé szigorúak, mint a Get<> hívások.

  • Bind lehetővé teszi egy absztrakt megvalósítását.
  • Get<>-nak/nak kell saját magának példányt létrehoznia.

A beállítások mintája

A beállítási minta használatakor alternatív módszer a szakasz kötése Position és hozzáadása a függőséginjektálási szolgáltatás tárolóhoz. A következő kódban PositionOptions hozzáadásra kerül a szolgáltatástárolóhoz Configure-sel és konfigurációhoz kötve:

using ConfigSample.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<PositionOptions>(
    builder.Configuration.GetSection(PositionOptions.Position));

var app = builder.Build();

Az előző kód használatával a következő kód felolvassa a pozícióbeállításokat:

public class Test2Model : PageModel
{
    private readonly PositionOptions _options;

    public Test2Model(IOptions<PositionOptions> options)
    {
        _options = options.Value;
    }

    public ContentResult OnGet()
    {
        return Content($"Title: {_options.Title} \n" +
                       $"Name: {_options.Name}");
    }
}

Az előző kódban az alkalmazás elindítása után a JSON-konfigurációs fájl módosításai nem lesznek beolvasva. Az alkalmazás elindítása utáni módosítások olvasásához használja az IOptionsSnapshot parancsot.

Beállítási felületek

IOptions<TOptions>:

IOptionsSnapshot<TOptions>:

IOptionsMonitor<TOptions>:

A konfiguráció utáni forgatókönyvek lehetővé teszik a beállítások beállítását vagy módosítását az összes IConfigureOptions<TOptions> konfiguráció után.

IOptionsFactory<TOptions> új beállításpéldányok létrehozásáért felelős. Egyetlen Create metódussal rendelkezik. Az alapértelmezett implementáció összegyűjti az összes regisztrált IConfigureOptions<TOptions> és IPostConfigureOptions<TOptions>, először futtatja az összes konfigurációt, majd végrehajtja a konfiguráció utáni műveleteket. Megkülönbözteti IConfigureNamedOptions<TOptions> és IConfigureOptions<TOptions> között, és csak a megfelelő felületet hívja meg.

IOptionsMonitorCache<TOptions>-t a IOptionsMonitor<TOptions> használja a TOptions példányok gyorsítótárazására. Az IOptionsMonitorCache<TOptions> érvényteleníti a figyelőben lévő beállításpéldányokat, hogy az értéket újraszámítsák TryRemove. Az értékek manuálisan is bevezethetők a TryAdd. A Clear metódus akkor használatos, ha az összes elnevezett példányt igény szerint újra létre kell hozni.

Frissített adatok olvasása az IOptionsSnapshot használatával

IOptionsSnapshot<TOptions> használata:

  • A rendszer kérésenként egyszer számítja ki a beállításokat, amikor a kérés teljes élettartama alatt hozzáférnek és gyorsítótáraznak.
  • Jelentős teljesítménycsökkenést okozhat, mivel egy rétegezett szolgáltatás , amely kérésenként újraszámításra kerül. További információkért tekintse meg ezt a GitHub-problémát , és javítsa a konfigurációs kötés teljesítményét.
  • A konfiguráció módosításai az alkalmazás elindítása után jelennek meg, amikor olyan konfigurációszolgáltatókat használ, amelyek támogatják a frissített konfigurációs értékek olvasását.

A különbség a következők között IOptionsMonitorIOptionsSnapshot van:

  • IOptionsMonitor Egy Singleton-szolgáltatás , amely bármikor lekéri az aktuális beállításértékeket, ami különösen hasznos az egyszeri függőségekben.
  • IOptionsSnapshot egy hatókörű szolgáltatás, és az IOptionsSnapshot<T> objektum létrehozásának időpontjában pillanatképet nyújt a lehetőségekről. A beállítási pillanatképek átmeneti és hatókörű függőségekhez használhatók.

Az alábbi kód a következőt használja IOptionsSnapshot<TOptions>.

public class TestSnapModel : PageModel
{
    private readonly MyOptions _snapshotOptions;

    public TestSnapModel(IOptionsSnapshot<MyOptions> snapshotOptionsAccessor)
    {
        _snapshotOptions = snapshotOptionsAccessor.Value;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_snapshotOptions.Option1} \n" +
                       $"Option2: {_snapshotOptions.Option2}");
    }
}

Az alábbi kód regisztrál egy konfigurációs példányt, amely a következőhöz kötődik: MyOptions.

using SampleApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<MyOptions>(
    builder.Configuration.GetSection("MyOptions"));

var app = builder.Build();

Az előző kódban a JSON-konfigurációs fájl módosításai az alkalmazás elindítása után beolvasásra kerülnek.

IOptionsMonitor

Az alábbi kód regisztrál egy konfigurációs példányt, amelyhez MyOptions kapcsolódik.

using SampleApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<MyOptions>(
    builder.Configuration.GetSection("MyOptions"));

var app = builder.Build();

Az alábbi példa IOptionsMonitor<TOptions>használ:

public class TestMonitorModel : PageModel
{
    private readonly IOptionsMonitor<MyOptions> _optionsDelegate;

    public TestMonitorModel(IOptionsMonitor<MyOptions> optionsDelegate )
    {
        _optionsDelegate = optionsDelegate;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_optionsDelegate.CurrentValue.Option1} \n" +
                       $"Option2: {_optionsDelegate.CurrentValue.Option2}");
    }
}

Az előző kódban alapértelmezés szerint a JSON-konfigurációs fájl módosításai az alkalmazás elindítása után jelennek meg.

Egyéni kulcsnév megadása konfigurációs tulajdonsághoz a következő használatával: ConfigurationKeyName

Alapértelmezés szerint a beállításosztály tulajdonságnevét használja a rendszer a konfigurációs forrás kulcsneveként. Ha a tulajdonság neve Title, akkor a konfigurációban a kulcs neve is Title.

A nevek megkülönböztetésekor az ConfigurationKeyName attribútum használatával megadhatja a kulcs nevét a konfigurációs forrásban. Ezzel a technikával a konfiguráció egyik tulajdonságát egy másik névvel rendelheti hozzá a kódhoz.

Ez akkor hasznos, ha a konfigurációs forrás tulajdonságneve nem érvényes C#-azonosító, vagy ha más nevet szeretne használni a kódban.

Vegyük például a következő beállításosztályt:

public class PositionOptionsWithConfigurationKeyName
{
    public const string Position = "Position";

    [ConfigurationKeyName("position-title")]
    public string Title { get; set; } = string.Empty;

    [ConfigurationKeyName("position-name")]
    public string Name { get; set; } = string.Empty;
}

A(z) Title és Name osztály tulajdonságai a position-title és position-name elemekhez a következő appsettings.json fájlban vannak kötve.

{
  "Position": {
    "position-title": "Editor",
    "position-name": "Joe Smith"
  }
}

Az elnevezett beállítások támogatása az IConfigureNamedOptions használatával

Elnevezett beállítások:

  • Akkor hasznos, ha több konfigurációs szakasz is ugyanahhoz a tulajdonsághoz kapcsolódik.
  • Megkülönbözteti a kis- és nagybetűket.

Fontolja meg a következő appsettings.json fájlt:

{
  "TopItem": {
    "Month": {
      "Name": "Green Widget",
      "Model": "GW46"
    },
    "Year": {
      "Name": "Orange Gadget",
      "Model": "OG35"
    }
  }
}

Ahelyett, hogy a TopItem:Month és TopItem:Year összekapcsolásához két osztályt hozna létre, az alábbi osztály használatos az egyes szakaszokhoz:

public class TopItemSettings
{
    public const string Month = "Month";
    public const string Year = "Year";

    public string Name { get; set; } = string.Empty;
    public string Model { get; set; } = string.Empty;
}

A következő kód konfigurálja a névvel ellátott beállításokat:

using SampleApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<TopItemSettings>(TopItemSettings.Month,
    builder.Configuration.GetSection("TopItem:Month"));
builder.Services.Configure<TopItemSettings>(TopItemSettings.Year,
    builder.Configuration.GetSection("TopItem:Year"));

var app = builder.Build();

Az alábbi kód a névvel ellátott beállításokat jeleníti meg:

public class TestNOModel : PageModel
{
    private readonly TopItemSettings _monthTopItem;
    private readonly TopItemSettings _yearTopItem;

    public TestNOModel(IOptionsSnapshot<TopItemSettings> namedOptionsAccessor)
    {
        _monthTopItem = namedOptionsAccessor.Get(TopItemSettings.Month);
        _yearTopItem = namedOptionsAccessor.Get(TopItemSettings.Year);
    }

    public ContentResult OnGet()
    {
        return Content($"Month:Name {_monthTopItem.Name} \n" +
                       $"Month:Model {_monthTopItem.Model} \n\n" +
                       $"Year:Name {_yearTopItem.Name} \n" +
                       $"Year:Model {_yearTopItem.Model} \n"   );
    }
}

Minden opció egy nevesített példány. IConfigureOptions<TOptions> példányokat úgy kezelik, mint amelyek a Options.DefaultName példányt célozzák meg, ami string.Empty. IConfigureNamedOptions<TOptions> is megvalósítja IConfigureOptions<TOptions>. Az alapértelmezett implementáció logikát tartalmaz, hogy az egyes elemeket megfelelően használja. A null névvel ellátott beállítás az összes elnevezett példányt megcélozza egy adott elnevezett példány helyett. ConfigureAll és PostConfigureAll használja ezt az egyezményt.

OptionsBuilder API

OptionsBuilder<TOptions> példányok konfigurálására van használva TOptions. OptionsBuilder Egyszerűbbé teszi az elnevezett beállítások létrehozását, mivel ez csak egy paraméter a kezdeti AddOptions<TOptions>(string optionsName) híváshoz, ahelyett, hogy az összes későbbi hívásban megjelenne. A beállítások érvényesítése és a ConfigureOptions szolgáltatásfüggőségeket elfogadó túlterhelések csak a OptionsBuilder elérhetők.

OptionsBuildera Beállítások érvényesítési szakaszában használható.

Lásd: Az AddOptions használata az egyéni tárház konfigurálásához az egyéni tárház hozzáadásával kapcsolatos információkért.

Beállítások konfigurálása a DI-szolgáltatások használatával

A szolgáltatások a függőséginjektálásból érhetők el, a beállítások kétféleképpen konfigurálhatók:

  • Adjon át egy konfigurációs delegátumot a ConfigureOptionsBuilder<TOptions> parancsnak. OptionsBuilder<TOptions> olyan túlterheléseket Configure biztosít, amelyek legfeljebb öt szolgáltatás használatát teszik lehetővé a beállítások konfigurálásához:

    builder.Services.AddOptions<MyOptions>("optionalName")
        .Configure<Service1, Service2, Service3, Service4, Service5>(
            (o, s, s2, s3, s4, s5) => 
                o.Property = DoSomethingWith(s, s2, s3, s4, s5));
    
  • Hozzon létre egy típust, amely megvalósítja IConfigureOptions<TOptions> vagy IConfigureNamedOptions<TOptions>, és regisztrálja a típust szolgáltatásként.

Javasoljuk, hogy adjon át egy konfigurációs delegáltat Configure-nek, mivel a szolgáltatás létrehozása összetettebb. A típus létrehozása egyenértékű azzal, amit a keretrendszer a híváskor Configurevégez. A hívás Configure egy átmeneti általánost IConfigureNamedOptions<TOptions>regisztrál, amelynek konstruktora elfogadja a megadott általános szolgáltatástípusokat.

Beállítások érvényesítése

A beállítások érvényesítése lehetővé teszi a beállításértékek érvényesítését.

Fontolja meg a következő appsettings.json fájlt:

{
  "MyConfig": {
    "Key1": "My Key One",
    "Key2": 10,
    "Key3": 32
  }
}

A következő osztály a konfigurációs szakaszhoz való kötésre "MyConfig" szolgál, és néhány DataAnnotations szabályt alkalmaz:

public class MyConfigOptions
{
    public const string MyConfig = "MyConfig";

    [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")]
    public string Key1 { get; set; }
    [Range(0, 1000,
        ErrorMessage = "Value for {0} must be between {1} and {2}.")]
    public int Key2 { get; set; }
    public int Key3 { get; set; }
}

A következő kód:

using OptionsValidationSample.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.AddOptions<MyConfigOptions>()
            .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
            .ValidateDataAnnotations();

var app = builder.Build();

A ValidateDataAnnotations bővítménymetódus a Microsoft.Extensions.Options.DataAnnotations NuGet-csomagban van definiálva. Az SDK-t használó Microsoft.NET.Sdk.Web webalkalmazások esetében a csomagra implicit módon hivatkozik a megosztott keretrendszer.

Az alábbi kód a konfigurációs értékeket vagy az érvényesítési hibákat jeleníti meg:

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly IOptions<MyConfigOptions> _config;

    public HomeController(IOptions<MyConfigOptions> config,
                          ILogger<HomeController> logger)
    {
        _config = config;
        _logger = logger;

        try
        {
            var configValue = _config.Value;

        }
        catch (OptionsValidationException ex)
        {
            foreach (var failure in ex.Failures)
            {
                _logger.LogError(failure);
            }
        }
    }

    public ContentResult Index()
    {
        string msg;
        try
        {
            msg = $"Key1: {_config.Value.Key1} \n" +
                  $"Key2: {_config.Value.Key2} \n" +
                  $"Key3: {_config.Value.Key3}";
        }
        catch (OptionsValidationException optValEx)
        {
            return Content(optValEx.Message);
        }
        return Content(msg);
    }

A következő kód egy összetettebb érvényesítési szabályt alkalmaz meghatalmazott használatával:

using OptionsValidationSample.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.AddOptions<MyConfigOptions>()
            .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
            .ValidateDataAnnotations()
        .Validate(config =>
        {
            if (config.Key2 != 0)
            {
                return config.Key3 > config.Key2;
            }

            return true;
        }, "Key3 must be > than Key2.");   // Failure message.

var app = builder.Build();

IValidateOptions<TOptions> és IValidatableObject

A következő osztály implementálja IValidateOptions<TOptions>:

public class MyConfigValidation : IValidateOptions<MyConfigOptions>
{
    public MyConfigOptions _config { get; private set; }

    public  MyConfigValidation(IConfiguration config)
    {
        _config = config.GetSection(MyConfigOptions.MyConfig)
            .Get<MyConfigOptions>();
    }

    public ValidateOptionsResult Validate(string name, MyConfigOptions options)
    {
        string? vor = null;
        var rx = new Regex(@"^[a-zA-Z''-'\s]{1,40}$");
        var match = rx.Match(options.Key1!);

        if (string.IsNullOrEmpty(match.Value))
        {
            vor = $"{options.Key1} doesn't match RegEx \n";
        }

        if ( options.Key2 < 0 || options.Key2 > 1000)
        {
            vor = $"{options.Key2} doesn't match Range 0 - 1000 \n";
        }

        if (_config.Key2 != default)
        {
            if(_config.Key3 <= _config.Key2)
            {
                vor +=  "Key3 must be > than Key2.";
            }
        }

        if (vor != null)
        {
            return ValidateOptionsResult.Fail(vor);
        }

        return ValidateOptionsResult.Success;
    }
}

IValidateOptions lehetővé teszi az érvényesítési kód Program.cs-ből való áthelyezését egy osztályba.

Az előző kód használatával az Program.cs ellenőrzés a következő kóddal van engedélyezve.

using Microsoft.Extensions.Options;
using OptionsValidationSample.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.Configure<MyConfigOptions>(builder.Configuration.GetSection(
                                        MyConfigOptions.MyConfig));

builder.Services.AddSingleton<IValidateOptions
                              <MyConfigOptions>, MyConfigValidation>();

var app = builder.Build();

A beállítások érvényesítése a következőt is támogatja IValidatableObject: Egy osztály osztályszintű ellenőrzésének végrehajtása magában az osztályban:

ValidateOnStart

A TOption példány első létrehozásakor fut a beállítások érvényesítése. Ez például azt jelenti, hogy amikor egy kérelemfolyamatban először férnek hozzá IOptionsSnapshot<TOptions>.Value-hoz, vagy amikor IOptionsMonitor<TOptions>.Get(string)-ot hívnak meg a meglévő beállításokon. A beállítások újbóli betöltése után az érvényesítés újra lefut. A ASP.NET Core-futtatókörnyezet a OptionsCache<TOptions> létrehozás után gyorsítótárazza a beállításpéldányt.

A beállítások ellenőrzésének azonnali futtatásához, az alkalmazás indításakor hívja fel a következőt ValidateOnStart<TOptions>(OptionsBuilder<TOptions>)Program.cs:

builder.Services.AddOptions<MyConfigOptions>()
    .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
    .ValidateDataAnnotations()
    .ValidateOnStart();

Beállítások a konfigurációt követően

Utókonfiguráció beállítása a következővel IPostConfigureOptions<TOptions>. A konfiguráció utáni futtatás az összes IConfigureOptions<TOptions> konfiguráció után megtörténik:

using OptionsValidationSample.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.AddOptions<MyConfigOptions>()
                .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig));

builder.Services.PostConfigure<MyConfigOptions>(myOptions =>
{
    myOptions.Key1 = "post_configured_key1_value";
});

PostConfigure a névvel ellátott beállítások utólagos konfigurálásához érhető el:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<TopItemSettings>(TopItemSettings.Month,
    builder.Configuration.GetSection("TopItem:Month"));
builder.Services.Configure<TopItemSettings>(TopItemSettings.Year,
    builder.Configuration.GetSection("TopItem:Year"));

builder.Services.PostConfigure<TopItemSettings>("Month", myOptions =>
{
    myOptions.Name = "post_configured_name_value";
    myOptions.Model = "post_configured_model_value";
});

var app = builder.Build();

A PostConfigureAll eszközt az összes konfigurációs példány utólagos konfigurálására használja:

using OptionsValidationSample.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.AddOptions<MyConfigOptions>()
                .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig));

builder.Services.PostConfigureAll<MyConfigOptions>(myOptions =>
{
    myOptions.Key1 = "post_configured_key1_value";
});

Hozzáférési beállítások a következőben: Program.cs

Az IOptions<TOptions> vagy IOptionsMonitor<TOptions> eléréséhez a Program.cs nevű helyen, hívja a GetRequiredService számot a következőhöz WebApplication.Services:

var app = builder.Build();

var option1 = app.Services.GetRequiredService<IOptionsMonitor<MyOptions>>()
    .CurrentValue.Option1;

További erőforrások

Kirk Larkin és Rick Anderson.

Az opciós minta osztályok használatával erősen típusos hozzáférést biztosít a kapcsolódó beállítások csoportjaihoz. Ha a konfigurációs beállításokat forgatókönyvek szerint külön osztályokba különítjük el, az alkalmazás két fontos szoftvermérnöki alapelvnek felel meg:

  • Encapsulation:
    • A konfigurációs beállításoktól függő osztályok csak az általuk használt konfigurációs beállításoktól függnek.
  • Az aggodalmak elkülönítése:
    • Az alkalmazás különböző részeinek beállításai nem függenek egymástól, és nincsenek összekapcsolva.

A beállítások emellett a konfigurációs adatok ellenőrzésére szolgáló mechanizmust is biztosítanak. További információt a Beállítások érvényesítési szakaszában talál.

Ez a cikk a ASP.NET Core beállítási mintájáról nyújt tájékoztatást. A beállítási minta konzolalkalmazásokban való használatáról további információt a .NET Beállítások mintája című témakörben talál.

Hierarchikus konfiguráció kötése

A kapcsolódó konfigurációs értékek olvasásának elsődleges módja a beállítási minta használata. Például a következő konfigurációs értékek olvasásához:

  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  }

Hozza létre a következő PositionOptions osztályt:

public class PositionOptions
{
    public const string Position = "Position";

    public string Title { get; set; } = String.Empty;
    public string Name { get; set; } = String.Empty;
}

Egy beállításosztály:

  • Nem lehet absztrakt, és nyilvános, paraméter nélküli konstruktorral kell rendelkeznie.
  • A típus összes nyilvános írási-olvasási tulajdonsága kötött.
  • A mezők nincsenek megkötve. Az előző kódban a Position nincs kötés alatt. A Position mező célja, hogy ne kelljen a "Position" sztringet kézzel kódolni az alkalmazásban, amikor az osztályt egy konfigurációs szolgáltatóhoz kötjük.

A következő kód:

  • A ConfigurationBinder.Bind meghívásával köti az osztályt PositionOptions a Position szakaszhoz.
  • Megjeleníti a Position konfigurációs adatokat.
public class Test22Model : PageModel
{
    private readonly IConfiguration Configuration;

    public Test22Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var positionOptions = new PositionOptions();
        Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

Az előző kódban alapértelmezés szerint a JSON-konfigurációs fájl módosításai az alkalmazás elindítása után jelennek meg.

ConfigurationBinder.Get<T> köti és visszaadja a megadott típust. ConfigurationBinder.Get<T> lehet, hogy kényelmesebb, mint a használata ConfigurationBinder.Bind. Az alábbi kód bemutatja, hogyan használható ConfigurationBinder.Get<T> az PositionOptions osztály:

public class Test21Model : PageModel
{
    private readonly IConfiguration Configuration;
    public PositionOptions? positionOptions { get; private set; }

    public Test21Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {            
        positionOptions = Configuration.GetSection(PositionOptions.Position)
                                                     .Get<PositionOptions>();

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

Az előző kódban alapértelmezés szerint a JSON-konfigurációs fájl módosításai az alkalmazás elindítása után jelennek meg.

A beállítási minta használatakor alternatív módszer a szakasz kötése Position és hozzáadása a függőséginjektálási szolgáltatás tárolóhoz. A következő kódban PositionOptions hozzáadásra kerül a szolgáltatástárolóhoz Configure-sel és konfigurációhoz kötve:

using ConfigSample.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<PositionOptions>(
    builder.Configuration.GetSection(PositionOptions.Position));

var app = builder.Build();

Az előző kód használatával a következő kód felolvassa a pozícióbeállításokat:

public class Test2Model : PageModel
{
    private readonly PositionOptions _options;

    public Test2Model(IOptions<PositionOptions> options)
    {
        _options = options.Value;
    }

    public ContentResult OnGet()
    {
        return Content($"Title: {_options.Title} \n" +
                       $"Name: {_options.Name}");
    }
}

Az előző kódban az alkalmazás elindítása után a JSON-konfigurációs fájl módosításai nem lesznek beolvasva. Az alkalmazás elindítása utáni módosítások olvasásához használja az IOptionsSnapshot parancsot.

Beállítási felületek

IOptions<TOptions>:

IOptionsSnapshot<TOptions>:

IOptionsMonitor<TOptions>:

A konfiguráció utáni forgatókönyvek lehetővé teszik a beállítások beállítását vagy módosítását az összes IConfigureOptions<TOptions> konfiguráció után.

IOptionsFactory<TOptions> új beállításpéldányok létrehozásáért felelős. Egyetlen Create metódussal rendelkezik. Az alapértelmezett implementáció összegyűjti az összes regisztrált IConfigureOptions<TOptions> és IPostConfigureOptions<TOptions>, először futtatja az összes konfigurációt, majd végrehajtja a konfiguráció utáni műveleteket. Megkülönbözteti IConfigureNamedOptions<TOptions> és IConfigureOptions<TOptions> között, és csak a megfelelő felületet hívja meg.

IOptionsMonitorCache<TOptions>-t a IOptionsMonitor<TOptions> használja a TOptions példányok gyorsítótárazására. Az IOptionsMonitorCache<TOptions> érvényteleníti a figyelőben lévő beállításpéldányokat, hogy az értéket újraszámítsák TryRemove. Az értékek manuálisan is bevezethetők a TryAdd. A Clear metódus akkor használatos, ha az összes elnevezett példányt igény szerint újra létre kell hozni.

Frissített adatok olvasása az IOptionsSnapshot használatával

IOptionsSnapshot<TOptions> használata:

  • A rendszer kérésenként egyszer számítja ki a beállításokat, amikor a kérés teljes élettartama alatt hozzáférnek és gyorsítótáraznak.
  • Jelentős teljesítménycsökkenést okozhat, mivel egy rétegezett szolgáltatás , amely kérésenként újraszámításra kerül. További információkért tekintse meg ezt a GitHub-problémát , és javítsa a konfigurációs kötés teljesítményét.
  • A konfiguráció módosításai az alkalmazás elindítása után jelennek meg, amikor olyan konfigurációszolgáltatókat használ, amelyek támogatják a frissített konfigurációs értékek olvasását.

A különbség a következők között IOptionsMonitorIOptionsSnapshot van:

  • IOptionsMonitor Egy Singleton-szolgáltatás , amely bármikor lekéri az aktuális beállításértékeket, ami különösen hasznos az egyszeri függőségekben.
  • IOptionsSnapshot egy hatókörű szolgáltatás, és az IOptionsSnapshot<T> objektum létrehozásának időpontjában pillanatképet nyújt a lehetőségekről. A beállítási pillanatképek átmeneti és hatókörű függőségekhez használhatók.

Az alábbi kód a következőt használja IOptionsSnapshot<TOptions>.

public class TestSnapModel : PageModel
{
    private readonly MyOptions _snapshotOptions;

    public TestSnapModel(IOptionsSnapshot<MyOptions> snapshotOptionsAccessor)
    {
        _snapshotOptions = snapshotOptionsAccessor.Value;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_snapshotOptions.Option1} \n" +
                       $"Option2: {_snapshotOptions.Option2}");
    }
}

Az alábbi kód regisztrál egy konfigurációs példányt, amely a következőhöz kötődik: MyOptions.

using SampleApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<MyOptions>(
    builder.Configuration.GetSection("MyOptions"));

var app = builder.Build();

Az előző kódban a JSON-konfigurációs fájl módosításai az alkalmazás elindítása után beolvasásra kerülnek.

IOptionsMonitor

Az alábbi kód regisztrál egy konfigurációs példányt, amelyhez MyOptions kapcsolódik.

using SampleApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<MyOptions>(
    builder.Configuration.GetSection("MyOptions"));

var app = builder.Build();

Az alábbi példa IOptionsMonitor<TOptions>használ:

public class TestMonitorModel : PageModel
{
    private readonly IOptionsMonitor<MyOptions> _optionsDelegate;

    public TestMonitorModel(IOptionsMonitor<MyOptions> optionsDelegate )
    {
        _optionsDelegate = optionsDelegate;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_optionsDelegate.CurrentValue.Option1} \n" +
                       $"Option2: {_optionsDelegate.CurrentValue.Option2}");
    }
}

Az előző kódban alapértelmezés szerint a JSON-konfigurációs fájl módosításai az alkalmazás elindítása után jelennek meg.

Az elnevezett beállítások támogatása az IConfigureNamedOptions használatával

Elnevezett beállítások:

  • Akkor hasznos, ha több konfigurációs szakasz is ugyanahhoz a tulajdonsághoz kapcsolódik.
  • Megkülönbözteti a kis- és nagybetűket.

Fontolja meg a következő appsettings.json fájlt:

{
  "TopItem": {
    "Month": {
      "Name": "Green Widget",
      "Model": "GW46"
    },
    "Year": {
      "Name": "Orange Gadget",
      "Model": "OG35"
    }
  }
}

Ahelyett, hogy a TopItem:Month és TopItem:Year összekapcsolásához két osztályt hozna létre, az alábbi osztály használatos az egyes szakaszokhoz:

public class TopItemSettings
{
    public const string Month = "Month";
    public const string Year = "Year";

    public string Name { get; set; } = string.Empty;
    public string Model { get; set; } = string.Empty;
}

A következő kód konfigurálja a névvel ellátott beállításokat:

using SampleApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<TopItemSettings>(TopItemSettings.Month,
    builder.Configuration.GetSection("TopItem:Month"));
builder.Services.Configure<TopItemSettings>(TopItemSettings.Year,
    builder.Configuration.GetSection("TopItem:Year"));

var app = builder.Build();

Az alábbi kód a névvel ellátott beállításokat jeleníti meg:

public class TestNOModel : PageModel
{
    private readonly TopItemSettings _monthTopItem;
    private readonly TopItemSettings _yearTopItem;

    public TestNOModel(IOptionsSnapshot<TopItemSettings> namedOptionsAccessor)
    {
        _monthTopItem = namedOptionsAccessor.Get(TopItemSettings.Month);
        _yearTopItem = namedOptionsAccessor.Get(TopItemSettings.Year);
    }

    public ContentResult OnGet()
    {
        return Content($"Month:Name {_monthTopItem.Name} \n" +
                       $"Month:Model {_monthTopItem.Model} \n\n" +
                       $"Year:Name {_yearTopItem.Name} \n" +
                       $"Year:Model {_yearTopItem.Model} \n"   );
    }
}

Minden opció egy nevesített példány. IConfigureOptions<TOptions> példányokat úgy kezelik, mint amelyek a Options.DefaultName példányt célozzák meg, ami string.Empty. IConfigureNamedOptions<TOptions> is megvalósítja IConfigureOptions<TOptions>. Az alapértelmezett implementáció logikát tartalmaz, hogy az egyes elemeket megfelelően használja. A null névvel ellátott beállítás az összes elnevezett példányt megcélozza egy adott elnevezett példány helyett. ConfigureAll és PostConfigureAll használja ezt az egyezményt.

OptionsBuilder API

OptionsBuilder<TOptions> példányok konfigurálására van használva TOptions. OptionsBuilder Egyszerűbbé teszi az elnevezett beállítások létrehozását, mivel ez csak egy paraméter a kezdeti AddOptions<TOptions>(string optionsName) híváshoz, ahelyett, hogy az összes későbbi hívásban megjelenne. A beállítások érvényesítése és a ConfigureOptions szolgáltatásfüggőségeket elfogadó túlterhelések csak a OptionsBuilder elérhetők.

OptionsBuildera Beállítások érvényesítési szakaszában használható.

Lásd: Az AddOptions használata az egyéni tárház konfigurálásához az egyéni tárház hozzáadásával kapcsolatos információkért.

Beállítások konfigurálása a DI-szolgáltatások használatával

A szolgáltatások a függőséginjektálásból érhetők el, a beállítások kétféleképpen konfigurálhatók:

  • Adjon át egy konfigurációs delegátumot a ConfigureOptionsBuilder<TOptions> parancsnak. OptionsBuilder<TOptions> olyan túlterheléseket Configure biztosít, amelyek legfeljebb öt szolgáltatás használatát teszik lehetővé a beállítások konfigurálásához:

    builder.Services.AddOptions<MyOptions>("optionalName")
        .Configure<Service1, Service2, Service3, Service4, Service5>(
            (o, s, s2, s3, s4, s5) => 
                o.Property = DoSomethingWith(s, s2, s3, s4, s5));
    
  • Hozzon létre egy típust, amely megvalósítja IConfigureOptions<TOptions> vagy IConfigureNamedOptions<TOptions>, és regisztrálja a típust szolgáltatásként.

Javasoljuk, hogy adjon át egy konfigurációs delegáltat Configure-nek, mivel a szolgáltatás létrehozása összetettebb. A típus létrehozása egyenértékű azzal, amit a keretrendszer a híváskor Configurevégez. A hívás Configure egy átmeneti általánost IConfigureNamedOptions<TOptions>regisztrál, amelynek konstruktora elfogadja a megadott általános szolgáltatástípusokat.

Beállítások érvényesítése

A beállítások érvényesítése lehetővé teszi a beállításértékek érvényesítését.

Fontolja meg a következő appsettings.json fájlt:

{
  "MyConfig": {
    "Key1": "My Key One",
    "Key2": 10,
    "Key3": 32
  }
}

A következő osztály a konfigurációs szakaszhoz való kötésre "MyConfig" szolgál, és néhány DataAnnotations szabályt alkalmaz:

public class MyConfigOptions
{
    public const string MyConfig = "MyConfig";

    [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")]
    public string Key1 { get; set; }
    [Range(0, 1000,
        ErrorMessage = "Value for {0} must be between {1} and {2}.")]
    public int Key2 { get; set; }
    public int Key3 { get; set; }
}

A következő kód:

using OptionsValidationSample.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.AddOptions<MyConfigOptions>()
            .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
            .ValidateDataAnnotations();

var app = builder.Build();

A ValidateDataAnnotations bővítménymetódus a Microsoft.Extensions.Options.DataAnnotations NuGet-csomagban van definiálva. Az SDK-t használó Microsoft.NET.Sdk.Web webalkalmazások esetében a csomagra implicit módon hivatkozik a megosztott keretrendszer.

Az alábbi kód a konfigurációs értékeket vagy az érvényesítési hibákat jeleníti meg:

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly IOptions<MyConfigOptions> _config;

    public HomeController(IOptions<MyConfigOptions> config,
                          ILogger<HomeController> logger)
    {
        _config = config;
        _logger = logger;

        try
        {
            var configValue = _config.Value;

        }
        catch (OptionsValidationException ex)
        {
            foreach (var failure in ex.Failures)
            {
                _logger.LogError(failure);
            }
        }
    }

    public ContentResult Index()
    {
        string msg;
        try
        {
            msg = $"Key1: {_config.Value.Key1} \n" +
                  $"Key2: {_config.Value.Key2} \n" +
                  $"Key3: {_config.Value.Key3}";
        }
        catch (OptionsValidationException optValEx)
        {
            return Content(optValEx.Message);
        }
        return Content(msg);
    }

A következő kód egy összetettebb érvényesítési szabályt alkalmaz meghatalmazott használatával:

using OptionsValidationSample.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.AddOptions<MyConfigOptions>()
            .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
            .ValidateDataAnnotations()
        .Validate(config =>
        {
            if (config.Key2 != 0)
            {
                return config.Key3 > config.Key2;
            }

            return true;
        }, "Key3 must be > than Key2.");   // Failure message.

var app = builder.Build();

IValidateOptions<TOptions> és IValidatableObject

A következő osztály implementálja IValidateOptions<TOptions>:

public class MyConfigValidation : IValidateOptions<MyConfigOptions>
{
    public MyConfigOptions _config { get; private set; }

    public  MyConfigValidation(IConfiguration config)
    {
        _config = config.GetSection(MyConfigOptions.MyConfig)
            .Get<MyConfigOptions>();
    }

    public ValidateOptionsResult Validate(string name, MyConfigOptions options)
    {
        string? vor = null;
        var rx = new Regex(@"^[a-zA-Z''-'\s]{1,40}$");
        var match = rx.Match(options.Key1!);

        if (string.IsNullOrEmpty(match.Value))
        {
            vor = $"{options.Key1} doesn't match RegEx \n";
        }

        if ( options.Key2 < 0 || options.Key2 > 1000)
        {
            vor = $"{options.Key2} doesn't match Range 0 - 1000 \n";
        }

        if (_config.Key2 != default)
        {
            if(_config.Key3 <= _config.Key2)
            {
                vor +=  "Key3 must be > than Key2.";
            }
        }

        if (vor != null)
        {
            return ValidateOptionsResult.Fail(vor);
        }

        return ValidateOptionsResult.Success;
    }
}

IValidateOptions lehetővé teszi az érvényesítési kód Program.cs-ből való áthelyezését egy osztályba.

Az előző kód használatával az Program.cs ellenőrzés a következő kóddal van engedélyezve.

using Microsoft.Extensions.Options;
using OptionsValidationSample.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.Configure<MyConfigOptions>(builder.Configuration.GetSection(
                                        MyConfigOptions.MyConfig));

builder.Services.AddSingleton<IValidateOptions
                              <MyConfigOptions>, MyConfigValidation>();

var app = builder.Build();

A beállítások érvényesítése a következőt is támogatja IValidatableObject: Egy osztály osztályszintű ellenőrzésének végrehajtása magában az osztályban:

ValidateOnStart

A beállítások érvényesítése az első alkalommal fut, amikor létrejön egy IOptions<TOptions>, IOptionsSnapshot<TOptions>vagy IOptionsMonitor<TOptions> implementáció. A beállítások azonnali ellenőrzéséhez, amikor az alkalmazás elindul, hívja meg a ValidateOnStart a Program.cs-ben:

builder.Services.AddOptions<MyConfigOptions>()
    .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
    .ValidateDataAnnotations()
    .ValidateOnStart();

Beállítások a konfigurációt követően

Utókonfiguráció beállítása a következővel IPostConfigureOptions<TOptions>. A konfiguráció utáni futtatás az összes IConfigureOptions<TOptions> konfiguráció után megtörténik:

using OptionsValidationSample.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.AddOptions<MyConfigOptions>()
                .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig));

builder.Services.PostConfigure<MyConfigOptions>(myOptions =>
{
    myOptions.Key1 = "post_configured_key1_value";
});

PostConfigure a névvel ellátott beállítások utólagos konfigurálásához érhető el:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<TopItemSettings>(TopItemSettings.Month,
    builder.Configuration.GetSection("TopItem:Month"));
builder.Services.Configure<TopItemSettings>(TopItemSettings.Year,
    builder.Configuration.GetSection("TopItem:Year"));

builder.Services.PostConfigure<TopItemSettings>("Month", myOptions =>
{
    myOptions.Name = "post_configured_name_value";
    myOptions.Model = "post_configured_model_value";
});

var app = builder.Build();

A PostConfigureAll eszközt az összes konfigurációs példány utólagos konfigurálására használja:

using OptionsValidationSample.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.AddOptions<MyConfigOptions>()
                .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig));

builder.Services.PostConfigureAll<MyConfigOptions>(myOptions =>
{
    myOptions.Key1 = "post_configured_key1_value";
});

Hozzáférési beállítások a következőben: Program.cs

Az IOptions<TOptions> vagy IOptionsMonitor<TOptions> eléréséhez a Program.cs nevű helyen, hívja a GetRequiredService számot a következőhöz WebApplication.Services:

var app = builder.Build();

var option1 = app.Services.GetRequiredService<IOptionsMonitor<MyOptions>>()
    .CurrentValue.Option1;

További erőforrások

Kirk Larkin és Rick Anderson.

Az opciós minta osztályok használatával erősen típusos hozzáférést biztosít a kapcsolódó beállítások csoportjaihoz. Ha a konfigurációs beállításokat forgatókönyvek szerint külön osztályokba különítjük el, az alkalmazás két fontos szoftvermérnöki alapelvnek felel meg:

  • Encapsulation:
    • A konfigurációs beállításoktól függő osztályok csak az általuk használt konfigurációs beállításoktól függnek.
  • Az aggodalmak elkülönítése:
    • Az alkalmazás különböző részeinek beállításai nem függenek egymástól, és nincsenek összekapcsolva.

A beállítások emellett a konfigurációs adatok ellenőrzésére szolgáló mechanizmust is biztosítanak. További információt a Beállítások érvényesítési szakaszában talál.

Ez a témakör a ASP.NET Core beállítási mintájáról nyújt tájékoztatást. A beállítási minta konzolalkalmazásokban való használatáról további információt a .NET Beállítások mintája című témakörben talál.

Mintakód megtekintése vagy letöltése (letöltés)

Hierarchikus konfiguráció kötése

A kapcsolódó konfigurációs értékek olvasásának elsődleges módja a beállítási minta használata. Például a következő konfigurációs értékek olvasásához:

  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  }

Hozza létre a következő PositionOptions osztályt:

public class PositionOptions
{
    public const string Position = "Position";

    public string Title { get; set; }
    public string Name { get; set; }
}

Egy beállításosztály:

  • Nem lehet absztrakt, és nyilvános, paraméter nélküli konstruktorral kell rendelkeznie.
  • A típus összes nyilvános írási-olvasási tulajdonsága kötött.
  • A mezők nincsenek megkötve. Az előző kódban a Position nincs kötés alatt. A Position tulajdonságot a rendszer úgy használja, hogy a sztringet "Position" ne kelljen keményen kódolni az alkalmazásban, amikor az osztályt egy konfigurációszolgáltatóhoz köti.

A következő kód:

  • A ConfigurationBinder.Bind meghívásával köti az osztályt PositionOptions a Position szakaszhoz.
  • Megjeleníti a Position konfigurációs adatokat.
public class Test22Model : PageModel
{
    private readonly IConfiguration Configuration;

    public Test22Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var positionOptions = new PositionOptions();
        Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

Az előző kódban alapértelmezés szerint a JSON-konfigurációs fájl módosításai az alkalmazás elindítása után jelennek meg.

ConfigurationBinder.Get<T> köti és visszaadja a megadott típust. ConfigurationBinder.Get<T> lehet, hogy kényelmesebb, mint a használata ConfigurationBinder.Bind. Az alábbi kód bemutatja, hogyan használható ConfigurationBinder.Get<T> az PositionOptions osztály:

public class Test21Model : PageModel
{
    private readonly IConfiguration Configuration;
    public PositionOptions positionOptions { get; private set; }

    public Test21Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {            
        positionOptions = Configuration.GetSection(PositionOptions.Position)
                                                     .Get<PositionOptions>();

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

Az előző kódban alapértelmezés szerint a JSON-konfigurációs fájl módosításai az alkalmazás elindítása után jelennek meg.

A beállítási minta használatakor alternatív módszer a szakasz kötése Position és hozzáadása a függőséginjektálási szolgáltatás tárolóhoz. A következő kódban PositionOptions hozzáadásra kerül a szolgáltatástárolóhoz Configure-sel és konfigurációhoz kötve:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<PositionOptions>(Configuration.GetSection(
                                        PositionOptions.Position));
    services.AddRazorPages();
}

Az előző kód használatával a következő kód felolvassa a pozícióbeállításokat:

public class Test2Model : PageModel
{
    private readonly PositionOptions _options;

    public Test2Model(IOptions<PositionOptions> options)
    {
        _options = options.Value;
    }

    public ContentResult OnGet()
    {
        return Content($"Title: {_options.Title} \n" +
                       $"Name: {_options.Name}");
    }
}

Az előző kódban az alkalmazás elindítása után a JSON-konfigurációs fájl módosításai nem lesznek beolvasva. Az alkalmazás elindítása utáni módosítások olvasásához használja az IOptionsSnapshot parancsot.

Beállítási felületek

IOptions<TOptions>:

IOptionsSnapshot<TOptions>:

IOptionsMonitor<TOptions>:

A konfiguráció utáni forgatókönyvek lehetővé teszik a beállítások beállítását vagy módosítását az összes IConfigureOptions<TOptions> konfiguráció után.

IOptionsFactory<TOptions> új beállításpéldányok létrehozásáért felelős. Egyetlen Create metódussal rendelkezik. Az alapértelmezett implementáció összegyűjti az összes regisztrált IConfigureOptions<TOptions> és IPostConfigureOptions<TOptions>, először futtatja az összes konfigurációt, majd végrehajtja a konfiguráció utáni műveleteket. Megkülönbözteti IConfigureNamedOptions<TOptions> és IConfigureOptions<TOptions> között, és csak a megfelelő felületet hívja meg.

IOptionsMonitorCache<TOptions>-t a IOptionsMonitor<TOptions> használja a TOptions példányok gyorsítótárazására. Az IOptionsMonitorCache<TOptions> érvényteleníti a figyelőben lévő beállításpéldányokat, hogy az értéket újraszámítsák TryRemove. Az értékek manuálisan is bevezethetők a TryAdd. A Clear metódus akkor használatos, ha az összes elnevezett példányt igény szerint újra létre kell hozni.

Frissített adatok olvasása az IOptionsSnapshot használatával

A IOptionsSnapshot<TOptions> beállításokat kérésenként egyszer számítja ki a rendszer, és gyorsítótárazza a kérés teljes élettartama alatt. A konfiguráció módosításai az alkalmazás elindítása után jelennek meg, amikor olyan konfigurációszolgáltatókat használ, amelyek támogatják a frissített konfigurációs értékek olvasását.

A különbség a következők között IOptionsMonitorIOptionsSnapshot van:

  • IOptionsMonitor Egy Singleton-szolgáltatás , amely bármikor lekéri az aktuális beállításértékeket, ami különösen hasznos az egyszeri függőségekben.
  • IOptionsSnapshot egy hatókörű szolgáltatás, és az IOptionsSnapshot<T> objektum létrehozásának időpontjában pillanatképet nyújt a lehetőségekről. A beállítási pillanatképek átmeneti és hatókörű függőségekhez használhatók.

Az alábbi kód a következőt használja IOptionsSnapshot<TOptions>.

public class TestSnapModel : PageModel
{
    private readonly MyOptions _snapshotOptions;

    public TestSnapModel(IOptionsSnapshot<MyOptions> snapshotOptionsAccessor)
    {
        _snapshotOptions = snapshotOptionsAccessor.Value;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_snapshotOptions.Option1} \n" +
                       $"Option2: {_snapshotOptions.Option2}");
    }
}

Az alábbi kód regisztrál egy konfigurációs példányt, amely a következőhöz kötődik: MyOptions.

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));

    services.AddRazorPages();
}

Az előző kódban a JSON-konfigurációs fájl módosításai az alkalmazás elindítása után beolvasásra kerülnek.

IOptionsMonitor

Az alábbi kód regisztrál egy konfigurációs példányt, amelyhez MyOptions kapcsolódik.

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));

    services.AddRazorPages();
}

Az alábbi példa IOptionsMonitor<TOptions>használ:

public class TestMonitorModel : PageModel
{
    private readonly IOptionsMonitor<MyOptions> _optionsDelegate;

    public TestMonitorModel(IOptionsMonitor<MyOptions> optionsDelegate )
    {
        _optionsDelegate = optionsDelegate;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_optionsDelegate.CurrentValue.Option1} \n" +
                       $"Option2: {_optionsDelegate.CurrentValue.Option2}");
    }
}

Az előző kódban alapértelmezés szerint a JSON-konfigurációs fájl módosításai az alkalmazás elindítása után jelennek meg.

Az elnevezett beállítások támogatása az IConfigureNamedOptions használatával

Elnevezett beállítások:

  • Akkor hasznos, ha több konfigurációs szakasz is ugyanahhoz a tulajdonsághoz kapcsolódik.
  • Megkülönbözteti a kis- és nagybetűket.

Fontolja meg a következő appsettings.json fájlt:

{
  "TopItem": {
    "Month": {
      "Name": "Green Widget",
      "Model": "GW46"
    },
    "Year": {
      "Name": "Orange Gadget",
      "Model": "OG35"
    }
  }
}

Ahelyett, hogy a TopItem:Month és TopItem:Year összekapcsolásához két osztályt hozna létre, az alábbi osztály használatos az egyes szakaszokhoz:

public class TopItemSettings
{
    public const string Month = "Month";
    public const string Year = "Year";

    public string Name { get; set; }
    public string Model { get; set; }
}

A következő kód konfigurálja a névvel ellátott beállításokat:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<TopItemSettings>(TopItemSettings.Month,
                                       Configuration.GetSection("TopItem:Month"));
    services.Configure<TopItemSettings>(TopItemSettings.Year,
                                        Configuration.GetSection("TopItem:Year"));

    services.AddRazorPages();
}

Az alábbi kód a névvel ellátott beállításokat jeleníti meg:

public class TestNOModel : PageModel
{
    private readonly TopItemSettings _monthTopItem;
    private readonly TopItemSettings _yearTopItem;

    public TestNOModel(IOptionsSnapshot<TopItemSettings> namedOptionsAccessor)
    {
        _monthTopItem = namedOptionsAccessor.Get(TopItemSettings.Month);
        _yearTopItem = namedOptionsAccessor.Get(TopItemSettings.Year);
    }

    public ContentResult OnGet()
    {
        return Content($"Month:Name {_monthTopItem.Name} \n" +
                       $"Month:Model {_monthTopItem.Model} \n\n" +
                       $"Year:Name {_yearTopItem.Name} \n" +
                       $"Year:Model {_yearTopItem.Model} \n"   );
    }
}

Minden opció egy nevesített példány. IConfigureOptions<TOptions> példányokat úgy kezelik, mint amelyek a Options.DefaultName példányt célozzák meg, ami string.Empty. IConfigureNamedOptions<TOptions> is megvalósítja IConfigureOptions<TOptions>. Az alapértelmezett implementáció logikát tartalmaz, hogy az egyes elemeket megfelelően használja. A null névvel ellátott beállítás az összes elnevezett példányt megcélozza egy adott elnevezett példány helyett. ConfigureAll és PostConfigureAll használja ezt az egyezményt.

OptionsBuilder API

OptionsBuilder<TOptions> példányok konfigurálására van használva TOptions. OptionsBuilder Egyszerűbbé teszi az elnevezett beállítások létrehozását, mivel ez csak egy paraméter a kezdeti AddOptions<TOptions>(string optionsName) híváshoz, ahelyett, hogy az összes későbbi hívásban megjelenne. A beállítások érvényesítése és a ConfigureOptions szolgáltatásfüggőségeket elfogadó túlterhelések csak a OptionsBuilder elérhetők.

OptionsBuildera Beállítások érvényesítési szakaszában használható.

Lásd: Az AddOptions használata az egyéni tárház konfigurálásához az egyéni tárház hozzáadásával kapcsolatos információkért.

Beállítások konfigurálása a DI-szolgáltatások használatával

A szolgáltatások a függőséginjektálásból érhetők el, a beállítások kétféleképpen konfigurálhatók:

  • Adjon át egy konfigurációs delegátumot a ConfigureOptionsBuilder<TOptions> parancsnak. OptionsBuilder<TOptions> olyan túlterheléseket Configure biztosít, amelyek legfeljebb öt szolgáltatás használatát teszik lehetővé a beállítások konfigurálásához:

    services.AddOptions<MyOptions>("optionalName")
        .Configure<Service1, Service2, Service3, Service4, Service5>(
            (o, s, s2, s3, s4, s5) => 
                o.Property = DoSomethingWith(s, s2, s3, s4, s5));
    
  • Hozzon létre egy típust, amely megvalósítja IConfigureOptions<TOptions> vagy IConfigureNamedOptions<TOptions>, és regisztrálja a típust szolgáltatásként.

Javasoljuk, hogy adjon át egy konfigurációs delegáltat Configure-nek, mivel a szolgáltatás létrehozása összetettebb. A típus létrehozása egyenértékű azzal, amit a keretrendszer a híváskor Configurevégez. A hívás Configure egy átmeneti általánost IConfigureNamedOptions<TOptions>regisztrál, amelynek konstruktora elfogadja a megadott általános szolgáltatástípusokat.

Beállítások érvényesítése

A beállítások érvényesítése lehetővé teszi a beállításértékek érvényesítését.

Fontolja meg a következő appsettings.json fájlt:

{
  "MyConfig": {
    "Key1": "My Key One",
    "Key2": 10,
    "Key3": 32
  }
}

A következő osztály a "MyConfig" konfigurációs szakaszhoz kötődik, és néhány DataAnnotations szabályt alkalmaz:

public class MyConfigOptions
{
    public const string MyConfig = "MyConfig";

    [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")]
    public string Key1 { get; set; }
    [Range(0, 1000,
        ErrorMessage = "Value for {0} must be between {1} and {2}.")]
    public int Key2 { get; set; }
    public int Key3 { get; set; }
}

A következő kód:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddOptions<MyConfigOptions>()
            .Bind(Configuration.GetSection(MyConfigOptions.MyConfig))
            .ValidateDataAnnotations();

        services.AddControllersWithViews();
    }

A ValidateDataAnnotations bővítménymetódus a Microsoft.Extensions.Options.DataAnnotations NuGet-csomagban van definiálva. Az SDK-t használó Microsoft.NET.Sdk.Web webalkalmazások esetében a csomagra implicit módon hivatkozik a megosztott keretrendszer.

Az alábbi kód a konfigurációs értékeket vagy az érvényesítési hibákat jeleníti meg:

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly IOptions<MyConfigOptions> _config;

    public HomeController(IOptions<MyConfigOptions> config,
                          ILogger<HomeController> logger)
    {
        _config = config;
        _logger = logger;

        try
        {
            var configValue = _config.Value;

        }
        catch (OptionsValidationException ex)
        {
            foreach (var failure in ex.Failures)
            {
                _logger.LogError(failure);
            }
        }
    }

    public ContentResult Index()
    {
        string msg;
        try
        {
             msg = $"Key1: {_config.Value.Key1} \n" +
                   $"Key2: {_config.Value.Key2} \n" +
                   $"Key3: {_config.Value.Key3}";
        }
        catch (OptionsValidationException optValEx)
        {
            return Content(optValEx.Message);
        }
        return Content(msg);
    }

A következő kód egy összetettebb érvényesítési szabályt alkalmaz meghatalmazott használatával:

public void ConfigureServices(IServiceCollection services)
{
    services.AddOptions<MyConfigOptions>()
        .Bind(Configuration.GetSection(MyConfigOptions.MyConfig))
        .ValidateDataAnnotations()
        .Validate(config =>
        {
            if (config.Key2 != 0)
            {
                return config.Key3 > config.Key2;
            }

            return true;
        }, "Key3 must be > than Key2.");   // Failure message.

    services.AddControllersWithViews();
}

IValidateOptions összetett ellenőrzéshez

A következő osztály implementálja IValidateOptions<TOptions>:

public class MyConfigValidation : IValidateOptions<MyConfigOptions>
{
    public MyConfigOptions _config { get; private set; }

    public  MyConfigValidation(IConfiguration config)
    {
        _config = config.GetSection(MyConfigOptions.MyConfig)
            .Get<MyConfigOptions>();
    }

    public ValidateOptionsResult Validate(string name, MyConfigOptions options)
    {
        string vor=null;
        var rx = new Regex(@"^[a-zA-Z''-'\s]{1,40}$");
        var match = rx.Match(options.Key1);

        if (string.IsNullOrEmpty(match.Value))
        {
            vor = $"{options.Key1} doesn't match RegEx \n";
        }

        if ( options.Key2 < 0 || options.Key2 > 1000)
        {
            vor = $"{options.Key2} doesn't match Range 0 - 1000 \n";
        }

        if (_config.Key2 != default)
        {
            if(_config.Key3 <= _config.Key2)
            {
                vor +=  "Key3 must be > than Key2.";
            }
        }

        if (vor != null)
        {
            return ValidateOptionsResult.Fail(vor);
        }

        return ValidateOptionsResult.Success;
    }
}

IValidateOptions lehetővé teszi az érvényesítési kód StartUp-ből való áthelyezését egy osztályba.

Az előző kód használatával az Startup.ConfigureServices ellenőrzés a következő kóddal van engedélyezve.

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyConfigOptions>(Configuration.GetSection(
                                        MyConfigOptions.MyConfig));
    services.TryAddEnumerable(ServiceDescriptor.Singleton<IValidateOptions
                              <MyConfigOptions>, MyConfigValidation>());
    services.AddControllersWithViews();
}

Beállítások a konfigurációt követően

Utókonfiguráció beállítása a következővel IPostConfigureOptions<TOptions>. A konfiguráció utáni futtatás az összes IConfigureOptions<TOptions> konfiguráció után megtörténik:

services.PostConfigure<MyOptions>(myOptions =>
{
    myOptions.Option1 = "post_configured_option1_value";
});

PostConfigure a névvel ellátott beállítások utólagos konfigurálásához érhető el:

services.PostConfigure<MyOptions>("named_options_1", myOptions =>
{
    myOptions.Option1 = "post_configured_option1_value";
});

A PostConfigureAll eszközt az összes konfigurációs példány utólagos konfigurálására használja:

services.PostConfigureAll<MyOptions>(myOptions =>
{
    myOptions.Option1 = "post_configured_option1_value";
});

Hozzáférés a beállításokhoz az indítás során

IOptions<TOptions> és IOptionsMonitor<TOptions> használható, Startup.Configuremivel a szolgáltatások a Configure metódus végrehajtása előtt jönnek létre.

public void Configure(IApplicationBuilder app, 
    IOptionsMonitor<MyOptions> optionsAccessor)
{
    var option1 = optionsAccessor.CurrentValue.Option1;
}

Ne használja a IOptions<TOptions> vagy IOptionsMonitor<TOptions> a Startup.ConfigureServices. A szolgáltatásregisztrációk megrendelése miatt inkonzisztens beállításállapot létezhet.

Options.ConfigurationExtensions NuGet-csomag

A Microsoft.Extensions.Options.ConfigurationExtensions csomag implicit módon hivatkozik ASP.NET Core-alkalmazásokban.