簡體   English   中英

ASP.NET Core appsettings.json 更新代碼

[英]ASP.NET Core appsettings.json update in code

我目前正在使用 asp.net core v1.1 進行項目,在我的 appsettings.json 中我有:

"AppSettings": {
   "AzureConnectionKey": "***",
   "AzureContainerName": "**",
   "NumberOfTicks": 621355968000000000,
   "NumberOfMiliseconds": 10000,
   "SelectedPvInstalationIds": [ 13, 137, 126, 121, 68, 29 ],
   "MaxPvPower": 160,
   "MaxWindPower": 5745.35
},

我也有用於存儲它們的類:

public class AppSettings
{
    public string AzureConnectionKey { get; set; }
    public string AzureContainerName { get; set; }
    public long NumberOfTicks { get; set; }
    public long NumberOfMiliseconds { get; set; }
    public int[] SelectedPvInstalationIds { get; set; }
    public decimal MaxPvPower { get; set; }
    public decimal MaxWindPower { get; set; }
}

然后在 Startup.cs 中啟用 DI:

services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));

有沒有辦法從控制器更改和保存MaxPvPowerMaxWindPower

我嘗試使用

private readonly AppSettings _settings;

public HomeController(IOptions<AppSettings> settings)
{
    _settings = settings.Value;
}

[Authorize(Policy = "AdminPolicy")]
 public IActionResult UpdateSettings(decimal pv, decimal wind)
 {
    _settings.MaxPvPower = pv;
    _settings.MaxWindPower = wind;

    return Redirect("Settings");
 }

但它什么也沒做。

基本上你可以像這樣在IConfiguration設置值:

IConfiguration configuration = ...
// ...
configuration["key"] = "value";

問題在於,例如JsonConfigurationProvider沒有實現將配置保存到文件中。 正如您在源代碼中看到的那樣,它沒有覆蓋ConfigurationProvider的 Set 方法。 (見來源

您可以創建自己的提供程序並在那里實現保存。 此處(實體框架自定義提供程序的基本示例)是如何執行此操作的示例。

這是微軟關於 .Net Core Apps 中的配置設置的相關文章:

Asp.Net 核心配置

該頁面還有示例代碼,這也可能會有所幫助。

更新

我認為內存中提供程序和綁定到 POCO 類可能有一些用處,但不能像 OP 預期的那樣工作。

下一個選項可以是設置reloadOnChange的參數AddJsonFile為true同時加入了配置文件並手動解析JSON配置文件和如預期更改。

    public class Startup
    {
        ...
        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                .AddEnvironmentVariables();
            Configuration = builder.Build();
        }
        ...
    }

... reloadOnChange僅在 ASP.NET Core 1.1 及更高版本中受支持。

我采用了 Qamar Zamans 代碼(謝謝)並對其進行了修改,以允許編輯大於:一個:層:深的參數。

希望它可以幫助某人,驚訝地發現這不是某個地方的圖書館功能。

public static class SettingsHelpers
{
    public static void AddOrUpdateAppSetting<T>(string sectionPathKey, T value)
    {
        try
        {
            var filePath = Path.Combine(AppContext.BaseDirectory, "appsettings.json");
            string json = File.ReadAllText(filePath);
            dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(json);

            SetValueRecursively(sectionPathKey, jsonObj, value);

            string output = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObj, Newtonsoft.Json.Formatting.Indented);
            File.WriteAllText(filePath, output);

        }
        catch (Exception ex)
        {
            Console.WriteLine("Error writing app settings | {0}", ex.Message);
        }
    }

    private static void SetValueRecursively<T>(string sectionPathKey, dynamic jsonObj, T value)
    {
        // split the string at the first ':' character
        var remainingSections = sectionPathKey.Split(":", 2);

        var currentSection = remainingSections[0];
        if (remainingSections.Length > 1)
        {
            // continue with the procress, moving down the tree
            var nextSection = remainingSections[1];
            SetValueRecursively(nextSection, jsonObj[currentSection], value);
        }
        else
        {
            // we've got to the end of the tree, set the value
            jsonObj[currentSection] = value; 
        }
    }

在運行時更新 ASP.NET Core 中的appsettings.json文件。

以這個示例appsettings.json文件為例:

{
  Config: {
     IsConfig: false
  }
}

這是將IsConfig屬性更新為 true 的代碼:

Main()
{
    AddOrUpdateAppSetting("Config:IsConfig", true);
}

public static void AddOrUpdateAppSetting<T>(string key, T value) 
{
    try 
    {
        var filePath = Path.Combine(AppContext.BaseDirectory, "appSettings.json");
        string json = File.ReadAllText(filePath);
        dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
                
        var sectionPath = key.Split(":")[0];

        if (!string.IsNullOrEmpty(sectionPath)) 
        {
            var keyPath = key.Split(":")[1];
            jsonObj[sectionPath][keyPath] = value;
        }
        else 
        {
            jsonObj[sectionPath] = value; // if no sectionpath just set the value
        }

        string output = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObj, Newtonsoft.Json.Formatting.Indented);
        File.WriteAllText(filePath, output);
    }
    catch (ConfigurationErrorsException) 
    {
        Console.WriteLine("Error writing app settings");
    }
}
    public static void SetAppSettingValue(string key, string value, string appSettingsJsonFilePath = null)
    {
        if (appSettingsJsonFilePath == null)
        {
            appSettingsJsonFilePath = System.IO.Path.Combine(System.AppContext.BaseDirectory, "appsettings.json");
        }

        var json =   System.IO.File.ReadAllText(appSettingsJsonFilePath);
        dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JObject>(json);

        jsonObj[key] = value;

        string output = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObj, Newtonsoft.Json.Formatting.Indented);

        System.IO.File.WriteAllText(appSettingsJsonFilePath, output);
    }

根據 Qamar Zaman 和 Alex Horlock 的代碼,我對其進行了一些更改。

 public static class SettingsHelpers
 {
    public static void AddOrUpdateAppSetting<T>(T value, IWebHostEnvironment webHostEnvironment)
    {
        try
        {
            var settingFiles = new List<string> { "appsettings.json", $"appsettings.{webHostEnvironment.EnvironmentName}.json" };
            foreach (var item in settingFiles)
            {


                var filePath = Path.Combine(AppContext.BaseDirectory, item);
                string json = File.ReadAllText(filePath);
                dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(json);

                SetValueRecursively(jsonObj, value);

                string output = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObj, Newtonsoft.Json.Formatting.Indented);
                File.WriteAllText(filePath, output);
            }
        }
        catch (Exception ex)
        {
            throw new Exception($"Error writing app settings | {ex.Message}", ex);
        }
    }



    private static void SetValueRecursively<T>(dynamic jsonObj, T value)
    {
        var properties = value.GetType().GetProperties();
        foreach (var property in properties)
        {
            var currentValue = property.GetValue(value);
            if (property.PropertyType.IsPrimitive || property.PropertyType == typeof(string) || property.PropertyType == typeof(decimal))
            {
                if (currentValue == null) continue;
                try
                {
                    jsonObj[property.Name].Value = currentValue;

                }
                catch (RuntimeBinderException)
                {
                    jsonObj[property.Name] = new JValue(currentValue);


                }
                continue;
            }
            try
            {
                if (jsonObj[property.Name] == null)
                {
                    jsonObj[property.Name] = new JObject();
                }

            }
            catch (RuntimeBinderException)
            {
                jsonObj[property.Name] = new JObject(new JProperty(property.Name));

            }
            SetValueRecursively(jsonObj[property.Name], currentValue);
        }


    }
}

假設 appsettings.json 有一個 eureka 端口,並且想要在 args (-p 5090) 中動態更改它。 通過這樣做,可以在創建許多服務時輕松更改 docker 的端口。

  "eureka": {
  "client": {
    "serviceUrl": "http://10.0.0.101:8761/eureka/",
    "shouldRegisterWithEureka": true,
    "shouldFetchRegistry": false 
  },
  "instance": {
    "port": 5000
  }
}


   public class Startup
   {
    public static string port = "5000";
    public Startup(IConfiguration configuration)
    {
        configuration["eureka:instance:port"] = port;

        Configuration = configuration;
    }


    public static void Main(string[] args)
    {
        int port = 5000;
        if (args.Length>1)
        {
            if (int.TryParse(args[1], out port))
            {
                Startup.port = port.ToString();
            }

        }
     }

我正在使用我自己的配置部分和我自己的強類型對象。 我總是用這個強類型對象注入 IOptions。 而且我可以在運行時更改配置。 對對象的范圍要非常小心。 請求范圍的對象獲取新的配置值。 我正在使用構造函數注入。

雖然這方面的文檔非常不清楚..我不確定這是否意味着。 閱讀此深入討論

我解決這個問題的方法是添加一個存儲在內存緩存中的“覆蓋”屬性。 例如,我的應用程序在“appSettings.json”文件中有一個“CacheEnabled”設置,用於確定是否緩存數據查詢結果。 在應用程序/數據庫測試期間,有時需要將此屬性設置為“false”。

通過管理員菜單,管理員可以覆蓋“CacheEnabled”設置。 決定是否啟用緩存的邏輯首先檢查覆蓋。 如果它沒有找到覆蓋值,則它使用“appSettings.json”值。

鑒於實現它所需的額外基礎設施,這對很多人來說可能不是一個好的解決方案。 然而,我的應用程序已經有一個緩存服務和一個管理員菜單,所以它很容易實現。

在我的項目中,我以這種方式使用 Active Directory 設置:

//...
public class Startup
{
    public void ConfigureServices(IServicesCollection services)
    {
        //...
        services.Configure<Ldap>(opts=> {
            opts.Url = "example.com";
            opts.UseSsl = true;
            opts.Port = 111;
            opts.BindDn = "CN=nn,OU=nn,OU=nn,DC=nn,DC=nn";
            opts.BindCredentials = "nn";
            opts.SearchBase = "DC=nn,DC=nn";
            opts.SearchFilter = "(&(objectClass=User){0})";
            opts.AdminCn = "CN=nn,OU=nn,OU=nn,DC=nn,DC=nn";
            opts.SearchGroupBase = "OU=nn,DC=nn,DC=nn";
        });
        //...
    }
}

所以,不使用 appsettings.json。


之后,我可以從控制器更新此設置:

//...
    [HttpPost("setActiveDirectorySettings")]
    public ActionResult<IOptions<Ldap>> SetActiveDirectorySettings(ActiveDirectorySettings clientActiveDirectorySettings)
    {
        LdapOptions.Value.Url = clientActiveDirectorySettings.Url;
        LdapOptions.Value.UseSsl = clientActiveDirectorySettings.UseSsl;
        LdapOptions.Value.Port = clientActiveDirectorySettings.Port;
        LdapOptions.Value.BindDn = clientActiveDirectorySettings.BindDn;
        LdapOptions.Value.BindCredentials = clientActiveDirectorySettings.BindCredentials;
        LdapOptions.Value.SearchBase = clientActiveDirectorySettings.SearchBase;
        LdapOptions.Value.SearchFilter = clientActiveDirectorySettings.SearchFilter;
        LdapOptions.Value.AdminCn = clientActiveDirectorySettings.AdminCn;
        LdapOptions.Value.SearchGroupBase = clientActiveDirectorySettings.SearchGroupBase;
        return Ok(LdapOptions.Value);
    }
//...

看起來它對我有用

基於@Alper Ebicoglu 的回答

得到:

// ===== || GET || GET appsettings.js property =====================================================================
[HttpGet]
[Route("GetNotificationDays")]
public async Task<IActionResult> GetNotificationDays()
{   
    
        var path = System.IO.Path.Combine(Directory.GetCurrentDirectory(), "appsettings.json");
        var json = await System.IO.File.ReadAllTextAsync(path);
        dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JObject>(json);
        return StatusCode(200, new { daysBefore = (int)jsonObj.InvoicementNotificationSettings.DaysBefore});
}

(int)jsonObj.InvoicementNotificationSettings.DaysBefore =

(int) = 轉換為 int - 取決於屬性

jsonObj = appsettings.js,

InvoicementNotificationSettings = appsettings.js 中的對象,

DaysBefore = InvoicementNotificationSettings 中的屬性

更新:appsettings.js

 // ===== || PUT || UPDATE appsettings.js property =====================================================================
    [HttpPut]
    [Route("SetNotificationDays")]
    public async Task<IActionResult> SetNotificationDays(int notificationDays)
    {
        if (notificationDays != 0)
        {
                 var path = System.IO.Path.Combine(Directory.GetCurrentDirectory(), "appsettings.json");
                 var json = await System.IO.File.ReadAllTextAsync(path);
                 dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JObject>(json);
                 jsonObj.InvoicementNotificationSettings.DaysBefore = notificationDays;
                 string output = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObj, Newtonsoft.Json.Formatting.Indented);
                 await System.IO.File.WriteAllTextAsync(path, output);
                 return await GetNotificationDays();
        }
        return StatusCode(409);
    }

如果從內存中讀取 appsettings:例如: int daysBefore = configuration.GetValue<int>("InvoicementNotificationSettings:DaysBefore");

比在 Startup.js - 更新后自動重新加載 appsettings.js

 public class Startup
    {
        public static IConfiguration Configuration { get; set; }

        // Constructor -----------------------------------------------------------------------------------------------------------------------------
        public Startup(IConfiguration configuration, Microsoft.Extensions.Hosting.IHostEnvironment env)
        {
            Configuration = configuration;

           // To autoreload appsettings.js after update -------------------------      
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                .AddEnvironmentVariables();
                Configuration = builder.Build();
        }

appsettings.js

{
  "ConnectionStrings": {
    "DefaultConnection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=ItlCrmsDb;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"
  },
  "InvoicementNotificationSettings": {
    "DaysBefore": 4
  },
   
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

在運行時修改 appsettings.json 有一個更簡單的答案。

Json 文件結構

var filePath = Path.Combine(System.AppContext.BaseDirectory, "appSettings.json");

string jsonString = System.IO.File.ReadAllText(filePath);

//use https://json2csharp.com/ to create the c# classes from your json
Root root = JsonSerializer.Deserialize<Root>(jsonString);

var dbtoadd = new Databas()
{
    Id = "myid",
    Name = "mynewdb",
    ConnectionString = ""
};

//add or change anything to this object like you do on any list
root.DatabaseSettings.Databases.Add(dbtoadd);

//serialize the new updated object to a string
string towrite = JsonSerializer.Serialize(root);

//overwrite the file and it wil contain the new data
System.IO.File.WriteAllText(filePath, towrite);

我看到大多數答案都使用Newtonsoft.Json包來更新設置。 如果您需要更新一層深的設置,您可以不使用Newtonsoft.Json並使用System.Text.Json (內置於 .Net Core 3.0 及更高版本)功能。 這是一個簡單的實現:

public void UpdateAppSetting(string key, string value)
{
    var configJson = File.ReadAllText("appsettings.json");
    var config = JsonSerializer.Deserialize<Dictionary<string, object>>(configJson);
    config[key] = value;
    var updatedConfigJson = JsonSerializer.Serialize(config, new JsonSerializerOptions { WriteIndented = true });
    File.WriteAllText("appsettings.json", updatedConfigJson);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM