λ·λ·μ Host κ°μ²΄λ DI, μ€μ , κ·Έλ¦¬κ³ , μ±μ μμ μ£ΌκΈ° κ΄λ ¨ λꡬλ₯Ό μ 곡ν©λλ€.
μΌλ°μ μΌλ‘ "νΈμ€νΈ"λΌκ³ νλ©΄ λ€νΈμν¬κ° μ°μλμ§λ§, λ·λ·μμλ λ€νΈμν¬λ₯Ό κ²°λΆνμ§ μμ κ°λ μΌλ‘ μ¬μ©ν©λλ€. λ€νΈμν¬ κΈ°λ₯μ κ²°λΆνμ¬,
WebHostλΌλ νμ κ°μ²΄λ μ 곡νκ³ , μ΄λ₯Ό κΈ°λ°ν μΉμ±μΌλ‘WebApplication(Asp.Net Core μ±) λ μ 곡ν©λλ€.
λ·λ·μμ "Configuration"μ μλ―Έλ (μ±μ μ¬λΉλ/μ¬μμ μμ΄) μ±μ νλΌλ―Έν°λ₯Ό μ€μ /λ³κ²½νλ κ²μ κ°λ¦¬ν΅λλ€. μ°Έκ³ λ‘ λ·λ· λ¬Έμ, VS μμλ "ꡬμ±"μ΄λΌκ³ λ²μνλλ°, μ΄ κΈμμλ "μ€μ "μ΄λΌκ³ ννν©λλ€.
λ·λ· Hostμ μ€μ μμ€ν
μ, μ€μ 곡κΈμ( λνμ μΌλ‘ JsonFileProvider - appsettings.json μ 컨ν
μΈ λ₯Ό μ€μ κ°μ μΆκ°)κ° μ 곡ν κ°μ μ½λμ 곡κΈν©λλ€.
곡κΈνλ λ°©μμ μλμ κ°μ΅λλ€.
- raw κ°μ κ·Έλλ‘ (μ΄ν μ½λμμ κ°μ²΄μ μλ λ°μΈλ©ν μ μμ)
ConfigurationBinderλ₯Ό ν΅ν΄ λ°μΈλ©λ κ°μ²΄
μ΄ κΈμ λ λ²μ§Έ λ°©μκ³Ό μ°κ΄λ, μ νμ μΈν°νμ΄μ€ ν¨λ°λ¦¬μ κ΄ν κ²μ λλ€.
μμ λ₯Ό μν΄,
μ€μ μμ€
appsettins.json
{
"Upstreams" : {
"Backends" : [ "https://app1.mysite.com", "https://app2.mysite.com" ]
}
}
λ°μΈλ© λͺ¨λΈ
public sealed class Upstreams // κΈ°λ³Έ μμ±μ μμ΄μΌ ν¨.
{
public Uri[] Backends { get; set; } = []; // get, set λͺ¨λ μμ΄μΌ ν¨.
}
μ€μ λ°μΈλ©μ μν λͺ¨λΈμ μλμ μꡬ μ¬νμ λ§μ‘±ν΄μΌ ν©λλ€.
- κΈ°λ³Έμμ±μ μ‘΄μ¬
- public read/write μμ±
μλ λ°μΈλ© μ€μ
// program.cs
builder.Configure<Upstreams>(builder.Configuration.GetSection("Upstreams"));
μ°Έκ³
Upstreams.BackendsλUri[]νμ μ΄κ³ ,appsettings.Upstreams.Backendsμ νμμstring[]νμ λλ€. μ€μ λ°μ΄λ© μμ,stringμ΄Uriμ μλ λ³νλλ νΈλ¦¬ κΈ°λ₯μ΄ μμ΅λλ€.
μλ λ°μΈλ© μ€μ μΌλ‘ μΈν΄, μ°λ¦¬ μ½λλ Upstreams κ°μ²΄λ₯Ό μλ μΈ κ°μ§ νμ
μ€ νλλ‘ μ νν΄μ λ°μ μ μμ΅λλ€.
- IOptions<Upstreams>
- IOptionsSnapshot<Upstreams>
- IOptionsMonitor<Upstreams>
IOptions<T>
Value μμ±μ μ²μμΌλ‘ μ½μ λ κ°μ΄ νμ λκ³ , μ΄ κ°μ μ±μ μ’
λ£κΉμ§ λ³νμ§ μμ΅λλ€.
class ScopedService(IOptions<Upstreams> upstreamsOptions)
{
public void Propagate()
{
var uptreams = upstreamsOptions.Value; // μ½κΈ°
// ...
μ£Όμμ βμ½κΈ°β λΌκ³ νμλ μ½λκ° μ²μμΌλ‘ μ€νλ λ(Lazy), IOptionsκ° μμ±λκ³ , μ΄ν appsettigns.json μ ν΅ν΄ κ°μ λ³κ²½νλλΌλ μ¬μμ±λμ§ μμ΅λλ€.
μ΄λ λ§μΉ μ±κΈν€ μλΉμ€μ μ μ¬νκ³ , μ€μ λ‘λ μ£Όμ λ°λλ° μ νμ΄ μμ΅λλ€.
IOptionsSnapshot<T>
λμΌνκ² Value μμ±μ μ 곡νμ§λ§, κ°μ²΄μ μλͺ
μ£ΌκΈ°λ Scope μ’
μμ μ
λλ€.
μ¦, Scope λ§λ€ μμ±λκ³ , μμ±λ λ κ°μ μ€μ κ°μ λ°μν©λλ€.
μ€μ½ν λ§λ€ λ°λμ νμΈν΄μΌ νλ κ°μ΄λΌλ©΄, μ΄ μΈν°νμ΄μ€λ₯Ό μ¬μ©ν΄μΌ ν©λλ€.
Scoped μλΉμ€μ λ§μ°¬κ°μ§λ‘, μ€μ½ν 컨ν μ€νΈ μλ μλΉμ€ κ²°μ (Service resolution) μ½λλ λ°νμ μλ¬λΌλ μ μ μ£Όμν΄μΌ ν©λλ€.
// λ°νμ μλ¬
var upstreamsOptions = sp.GetRequiredService<IOptionsSnapshot<UpStreams>>();
λ°λμ μ€μ½ν λ΄λΆμμ μμ±ν΄μΌ ν©λλ€.
using var scope = serviceProvider.CreateScope();
var upstreamsOptions = scope.ServiceProvider
.GetRequiredService<IOptionsSnapshot<UpStreams>>();
var upstreams = upstreamsOptions.Value;
IOptionsMonitor<T>
μ΄ μΈν°νμ΄μ€λ λ€λ₯Έ νμ λ€κ³Ό λ€λ₯΄κ² CurrnetValue μμ±μ μ 곡νλλ°, μ΄ μμ±μ κ°μ΄ μ€μ κ°(appsettings.json)κ³Ό 리μΌνμμΌλ‘ μΌμΉν¨μ 보μ₯ν©λλ€.
μ€μ νμΌμ λ³κ²½ μ¬νμ μ€μκ°μΌλ‘ μκ³ μΆμ λ μ΄ κ°μ²΄λ₯Ό μ¬μ©νλ©΄ λλλ°, κ·Έ μμ€μ νλκ° μμ λ‘ μ°μΈ Upstreams κ°μ²΄μΌ κ²μ
λλ€.
life-time μ μ±κΈν΄μΌλ‘ μμ±/μ£Όμ μ νΉλ³ν μ£Όμκ° νμμΉ μμ΅λλ€.
λν OnChange λΌλ μ΄λ²€νΈλ₯Ό μ 곡νλλ°, μ€μ κ°μ λ³κ²½μ΄ μμ λ λ°νλμ΄ λ°μ΄ν° λ°μΈλ© λ±, λ°νμ-ꡬλ
μ ν¨ν΄μ μ½λμ μ μ©ν©λλ€.
μΈν°νμ΄μ€ λ³ μ±λ₯
Value λ CurrentValue λ₯Ό μ½μ λλ νΉλ³ν μ±λ₯ μ€λ²ν€λλ μλ€κ³ ν©λλ€.
λ€λ§, IOptionsMonitor<T>.OnChange μ λ§μ ꡬλ
μκ° λ±λ‘λ κ²½μ°μλ ν΄λΌμ΄μΈνΈ μ½λ μ±λ₯μ μν₯μ μ€ μ μμ΄, λ¬΄κ±°μ΄ μ΄λ²€νΈ νΈλ€λ¬λ κ°κΈμ λΉλκΈ° ν¨ν΄μΌλ‘ ꡬννλ κ²μ΄ κΆκ³ λ©λλ€.
options.OnChanged += async (value, name) => { await Task.Run(() => { }, value); };