2016-12-05 30 views
9

in the official documentation açıklandığı gibi IOptions desenini kullanıyorum.Değerler appsetting.json'a nasıl güncellenir?

appsetting.json değerlerini okuduğumda bu iyi çalışır, ancak değerleri nasıl günceller ve değişiklikleri appsetting.json'a geri yüklerim?

Benim durumumda, kullanıcı arabiriminden düzenlenebilen birkaç alanım var (uygulamada yönetici kullanıcı tarafından). Bu nedenle, bu değerleri seçenek erişimcisi aracılığıyla güncellemek için ideal bir yaklaşım arıyorum.

+1

çerçeve yapılandırma değerlerini okumak için ortak bir altyapı sağlar, onları değiştirmek değil. Değişiklik söz konusu olduğunda, temel yapılandırma kaynağına erişmek ve değiştirmek için belirli yapılandırma sağlayıcısını kullanmanız gerekir. – haim770

+0

"temel yapılandırma kaynağına erişmek ve değiştirmek için özel yapılandırma sağlayıcısı"? Başlamak için bana biraz referans verebilir misiniz? – 439

+0

Değiştirmek istediğiniz yapılandırma kaynağı nedir? – haim770

cevap

10

Bu yanıtın yazıldığı sırada, appsettings.json numaralı yapılandırma değerlerini yazmaya yönelik işlevselliği olan Microsoft.Extensions.Options paketi tarafından sağlanan hiçbir bileşen bulunmadığı görülmüştür.

benim ASP.NET Core projelerinden biri ben bazı uygulama ayarlarını değiştirmek için kullanıcı etkinleştirme istedi - ve bu ayar değerleri eğer varsa yapılandırmaya eklenen alır isteğe bağlı bir appsettings.custom.json dosyasında daha precisly, appsettings.json saklanmalıdır. Bunun gibi

...
public Startup(IHostingEnvironment env) 
{ 
    IConfigurationBuilder builder = new ConfigurationBuilder() 
     .SetBasePath(env.ContentRootPath) 
     .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) 
     .AddJsonFile("appsettings.custom.json", optional: true, reloadOnChange: true) 
     .AddEnvironmentVariables(); 

    this.Configuration = builder.Build(); 
} 

Ben IOptions<T> uzanır IWritableOptions<T> arayüzü ilan; Bu yüzden ayarları okumak ve yazmak istediğimde IOptions<T>'u IWritableOptions<T> ile değiştirebilirim.

public interface IWritableOptions<out T> : IOptions<T> where T : class, new() 
{ 
    void Update(Action<T> applyChanges); 
} 

Ayrıca, bir yapılandırma bölümünü güncelleştirmek için IWritableOptions<T> tarafından kullanılmak üzere tasarlanmıştır bir bileşeni olan IOptionsWriter ile geldi. Bu daha önce belirtilen arayüzleri için benim uygulama ...

class OptionsWriter : IOptionsWriter 
{ 
    private readonly IHostingEnvironment environment; 
    private readonly IConfigurationRoot configuration; 
    private readonly string file; 

    public OptionsWriter(
     IHostingEnvironment environment, 
     IConfigurationRoot configuration, 
     string file) 
    { 
     this.environment = environment; 
     this.configuration = configuration; 
     this.file = file; 
    } 

    public void UpdateOptions(Action<JObject> callback, bool reload = true) 
    { 
     IFileProvider fileProvider = this.environment.ContentRootFileProvider; 
     IFileInfo fi = fileProvider.GetFileInfo(this.file); 
     JObject config = fileProvider.ReadJsonFileAsObject(fi); 
     callback(config); 
     using (var stream = File.OpenWrite(fi.PhysicalPath)) 
     { 
      stream.SetLength(0); 
      config.WriteTo(stream); 
     } 

     this.configuration.Reload(); 
    } 
} 

yazar dosya yapısı hakkında haberdar olmadığı için, ben JObject nesneler olarak bölümler işlemek için karar olduğunu. Erişimci istenen bölümü bulmaya çalışır ve T örneğine gönderir, geçerli değeri kullanır (bulunmazsa) veya T yeni bir örnek oluşturur, geçerli değer null ise. Bu tutucu nesne, değişiklikleri ona uygulayacak olan arayana iletilir. Değiştirilen nesne bölümünü yerine gidiyor bir JToken örneği ... Nihayet

class WritableOptions<T> : IWritableOptions<T> where T : class, new() 
{ 
    private readonly string sectionName; 
    private readonly IOptionsWriter writer; 
    private readonly IOptionsMonitor<T> options; 

    public WritableOptions(
     string sectionName, 
     IOptionsWriter writer, 
     IOptionsMonitor<T> options) 
    { 
     this.sectionName = sectionName; 
     this.writer = writer; 
     this.options = options; 
    } 

    public T Value => this.options.CurrentValue; 

    public void Update(Action<T> applyChanges) 
    { 
     this.writer.UpdateOptions(opt => 
     { 
      JToken section; 
      T sectionObject = opt.TryGetValue(this.sectionName, out section) ? 
       JsonConvert.DeserializeObject<T>(section.ToString()) : 
       this.options.CurrentValue ?? new T(); 

      applyChanges(sectionObject); 

      string json = JsonConvert.SerializeObject(sectionObject); 
      opt[this.sectionName] = JObject.Parse(json); 
     }); 
    } 
} 

geri dönüştürülmüş olur daha, ben ...

beni kolayca yazılabilir seçenekleri erişimci yapılandırmak için izin IServicesCollection için bir uzantısı yöntemi uygulamaya benim Controller cl olarak
static class ServicesCollectionExtensions 
{ 
    public static void ConfigureWritable<T>(
     this IServiceCollection services, 
     IConfigurationRoot configuration, 
     string sectionName, 
     string file) where T : class, new() 
    { 
     services.Configure<T>(configuration.GetSection(sectionName)); 

     services.AddTransient<IWritableOptions<T>>(provider => 
     { 
      var environment = provider.GetService<IHostingEnvironment>(); 
      var options = provider.GetService<IOptionsMonitor<T>>(); 
      IOptionsWriter writer = new OptionsWriter(environment, configuration, file); 
      return new WritableOptions<T>(sectionName, writer, options); 
     }); 
    } 
} 
ConfigureServices gibi kullanılabilecek

...

services.ConfigureWritable<CustomizableOptions>(this.Configuration, 
    "MySection", "appsettings.custom.json"); 

eşek sadece IOptions<T> ile aynı özelliklere sahip bir IWritableOptions<CustomizableOptions> örneğini talep edebilir, ancak aynı zamanda yapılandırma değerlerini değiştirip depolamasına izin verir.

private IWritableOptions<CustomizableOptions> options; 

... 

this.options.Update((opt) => { 
    opt.SampleOption = "..."; 
}); 
+0

Çok teşekkür ederim. [IConfigurationRoot'] ile ilgili bir sorum var (https://stackoverflow.com/questions/48939567/how-to-access-iconfigurationroot-in-startup-on-net-core-2), belki de Cevap :) –

6

matze cevabı basitleştirilmiş versiyonu:

public interface IWritableOptions<out T> : IOptionsSnapshot<T> where T : class, new() 
{ 
    void Update(Action<T> applyChanges); 
} 

public class WritableOptions<T> : IWritableOptions<T> where T : class, new() 
{ 
    private readonly IHostingEnvironment _environment; 
    private readonly IOptionsMonitor<T> _options; 
    private readonly string _section; 
    private readonly string _file; 

    public WritableOptions(
     IHostingEnvironment environment, 
     IOptionsMonitor<T> options, 
     string section, 
     string file) 
    { 
     _environment = environment; 
     _options = options; 
     _section = section; 
     _file = file; 
    } 

    public T Value => _options.CurrentValue; 
    public T Get(string name) => _options.Get(name); 

    public void Update(Action<T> applyChanges) 
    { 
     var fileProvider = _environment.ContentRootFileProvider; 
     var fileInfo = fileProvider.GetFileInfo(_file); 
     var physicalPath = fileInfo.PhysicalPath; 

     var jObject = JsonConvert.DeserializeObject<JObject>(File.ReadAllText(physicalPath)); 
     var sectionObject = jObject.TryGetValue(_section, out JToken section) ? 
      JsonConvert.DeserializeObject<T>(section.ToString()) : (Value ?? new T()); 

     applyChanges(sectionObject); 

     jObject[_section] = JObject.Parse(JsonConvert.SerializeObject(sectionObject)); 
     File.WriteAllText(physicalPath, JsonConvert.SerializeObject(jObject, Formatting.Indented)); 
    } 
} 

public static class ServiceCollectionExtensions 
{ 
    public static void ConfigureWritable<T>(
     this IServiceCollection services, 
     IConfigurationSection section, 
     string file = "appsettings.json") where T : class, new() 
    { 
     services.Configure<T>(section); 
     services.AddTransient<IWritableOptions<T>>(provider => 
     { 
      var environment = provider.GetService<IHostingEnvironment>(); 
      var options = provider.GetService<IOptionsMonitor<T>>(); 
      return new WritableOptions<T>(environment, options, section.Key, file); 
     }); 
    } 
} 

Kullanımı: Sonra

services.ConfigureWritable<MyOptions>(Configuration.GetSection("MySection")); 

:

0:

private readonly IWritableOptions<MyOptions> _options; 

public MyClass(IWritableOptions<MyOptions> options) 
{ 
    _options = options; 
} 

dosyadaki değişiklikleri kaydetmek için

_options.Update(opt => { 
    opt.Field1 = "value1"; 
    opt.Field2 = "value2"; 
}); 

Ve isteğe bağlı parametre (varsayılan olarak appsettings.json kullanacağız) olarak özel bir json dosyası geçirebilirsiniz:

services.ConfigureWritable<MyOptions>(Configuration.GetSection("MySection"), "appsettings.custom.json");