programing

코드의 ASP.NET Core appsettings.json 업데이트

yellowcard 2023. 4. 5. 21:29
반응형

코드의 ASP.NET Core appsettings.json 업데이트

현재 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; }
}

DI는 Startup.cs에서 사용할 수 있습니다.

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

변경하고 저장할 수 있는 방법이 있나요?MaxPvPower그리고.MaxWindPower콘트롤러에서?

나는 그것을 사용해봤어요.

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그럼 Configuration이 파일에 저장되지 않습니다.소스에서 알 수 있듯이 Set 메서드는 덮어쓰지 않습니다.ConfigurationProvider. (출처 참조)

독자적인 프로바이더를 작성해, 거기에 보존을 실장할 수 있습니다.여기(Entity Framework 커스텀 프로바이더의 기본 샘플)는 그 방법의 예입니다.

에서의 설정 설정에 관한 Microsoft의 관련 문서를 다음에 나타냅니다.넷 코어 애플리케이션:

Asp.Net 코어 설정

페이지에는 샘플 코드도 포함되어 있어 도움이 될 수 있습니다.

갱신하다

In-memory provider POCO 클래스에 대한 바인딩은 유용하다고 생각했지만 OP의 예상대로 작동하지 않습니다.

다음 옵션은 다음과 같습니다.reloadOnChange설정 파일을 추가하고 JSON Configuration파일을 수동으로 해석하여 원하는 대로 변경할 때 AddJsonFile 파라미터를 true로 설정합니다.

    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 이후

갱신하다appsettings.json파일을 ASP에 저장합니다.실행 시 NET Core.

이 샘플을 가져가세요.appsettings.json파일:

{
  Config: {
     IsConfig: false
  }
}

업데이트할 코드입니다.IsConfigtrue 속성:

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");
    }
}

Qamar Zamans 코드(감사합니다)를 가져와서 파라미터 편집에 사용할 수 있도록 수정했습니다.파라미터는 1층보다 더 깊습니다.

이게 어디선가 도서관 기능이 아니라는 사실에 놀라는 누군가가 도움이 되길 바랍니다.

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; 
        }
    }
    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);
    }

카마르 자만과 알렉스 호록의 코드에 따라 조금 바꿨습니다.

 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);
        }


    }
}

대부분의 답변이 사용되었습니다.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);
}

appsettings.json에 eureka 포트가 있으며 args(-p 5090)에서 동적으로 변경하려고 합니다.이렇게 하면 많은 서비스를 작성할 때 도커가 쉽게 포트를 변경할 수 있습니다.

  "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을 수정하기 위한 자세한 답변이 있습니다.

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);

이 문제를 해결하는 방법은 메모리 캐시에 "덮어쓰기" 속성을 추가하는 것입니다.예를 들어 어플리케이션의 "appSettings.json" 파일에 데이터 쿼리 결과의 캐시 여부를 결정하는 "CacheEnabled" 설정이 있습니다.응용 프로그램/DB 테스트 중에 이 속성을 "false"로 설정하는 것이 바람직할 수 있습니다.

관리자는 관리자 메뉴를 통해 "CacheEnabled" 설정을 재정의할 수 있습니다.캐시가 네이블인지 아닌지를 결정하는 로직은 우선 오버라이드를 확인합니다.재정의 값을 찾을 수 없는 경우 "appSettings.json" 값을 사용합니다.

이 솔루션을 구현하기 위해 필요한 추가 인프라를 고려할 때 많은 사용자에게 이 솔루션은 적합하지 않을 수 있습니다.다만, 애플리케이션에는 이미 캐싱 서비스도 있고 관리자 메뉴도 있기 때문에, 실장은 꽤 간단했습니다.

프로젝트에서는 Active Directory Settings를 다음과 같이 사용하고 있습니다.

//...
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.Invoice Notification Settings(청구서 통지 설정).일전 =

    (int) = cast to int - depending on the property
    
    jsonObj = appsettings.js,
    
    InvoicementNotificationSettings = object in appsettings.js,
    
    DaysBefore = property in InvoicementNotificationSettings

업데이트: 앱 설정.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);
    }

메모리에서 앱 설정을 읽는 경우: 예:int daysBefore = configuration.GetValue<int>("InvoicementNotificationSettings:DaysBefore");

Than In 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();
        }

어플리케이션 설정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": "*"
}

언급URL : https://stackoverflow.com/questions/41653688/asp-net-core-appsettings-json-update-in-code

반응형