C# – Come aggiornare a livello di codice il file User Secrets

 C Programming >> Programmazione C >  >> Tags >> File
C# – Come aggiornare a livello di codice il file User Secrets

I segreti utente sono archiviati in secrets.json. Questo file è specifico per la tua applicazione. Una volta che conosci il percorso di secrets.json, puoi caricarlo e aggiornarlo.

Ecco un esempio di come aggiornare secrets.json a livello di codice:

using Microsoft.Extensions.Configuration.UserSecrets;

//1. Find secrets.json
var secretsId = Assembly.GetExecutingAssembly().GetCustomAttribute<UserSecretsIdAttribute>().UserSecretsId;
var secretsPath = PathHelper.GetSecretsPathFromSecretsId(secretsId);

//2. Load and modify
var secretsJson = File.ReadAllText(secretsPath);
dynamic secrets = JsonConvert.DeserializeObject<ExpandoObject>(secretsJson, new ExpandoObjectConverter());
secrets.Password = "bye";

//3. Overwrite the file with changes
var updatedSecretsJson = JsonConvert.SerializeObject(secrets, Formatting.Indented);
File.WriteAllText(secretsPath, updatedSecretsJson);
Code language: C# (cs)

Nota:1) Per brevità, questo non mostra tutte le istruzioni using. 2) Questo sta usando Newtonsoft perché è migliore di System.Text.Json nella deserializzazione su oggetti dinamici.

Uno scenario reale in cui vorresti farlo è il seguente:se stai usando User Secrets e aggiornando appsettings.json a livello di codice, noterai che l'aggiornamento di una proprietà in appsettings.json è inutile se quella proprietà viene sovrascritta in secrets.json. Per modificare effettivamente il valore della proprietà, puoi aggiornarlo in secrets.json a livello di codice.

In questo articolo entrerò più nel dettaglio e spiegherò come funziona.

Come trovare secrets.json

Il file secrets.json è archiviato nel seguente percorso (su Windows):

%APPDATA%\Microsoft\UserSecrets\<user_secrets_id>\secrets.jsonCode language: plaintext (plaintext)

La parte del percorso è specifica per il tuo progetto. Quando aggiungi il file dei segreti utente, viene generato un identificatore univoco e aggiunto come proprietà al file .csproj:

<PropertyGroup>
	<OutputType>Exe</OutputType>
	<TargetFramework>netcoreapp3.1</TargetFramework>
	<UserSecretsId>fccaadfc-3ce2-4efe-8ca6-a4144e965323</UserSecretsId>
</PropertyGroup>
Code language: HTML, XML (xml)

Quando si esegue una compilazione, questa proprietà UserSecretsId viene inclusa come metadati dell'assembly. Ciò significa che puoi ottenere il valore con la riflessione:

using System.Reflection;

var secretsId = Assembly.GetExecutingAssembly().GetCustomAttribute<UserSecretsIdAttribute>().UserSecretsId;
Code language: C# (cs)

Una volta che hai questo ID segreto, puoi ottenere il percorso completo. Raccomando di utilizzare l'assistente di percorso per risolvere il percorso:

Microsoft.Extensions.Configuration.UserSecrets.PathHelper.GetSecretsPathFromSecretsId(secretsId)
Code language: C# (cs)

Caricamento di secrets.json e modifica dei valori

Una volta ottenuto il percorso, puoi caricare secrets.json e deserializzarlo in un oggetto dinamico. Ciò consente di modificare i valori. Una volta terminate le modifiche, puoi serializzare l'oggetto dinamico e sovrascrivere secrets.json per salvare le modifiche:

using System.Dynamic;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

var secretsJson = File.ReadAllText(secretsPath);
dynamic secrets = JsonConvert.DeserializeObject<ExpandoObject>(secretsJson, new ExpandoObjectConverter());
secrets.Password = "bye";

var updatedSecretsJson = JsonConvert.SerializeObject(secrets, Formatting.Indented);
File.WriteAllText(secretsPath, updatedSecretsJson);
Code language: C# (cs)

Assicurati di scrivere il JSON come rientrato perché secrets.json è un file di configurazione e deve essere leggibile dall'uomo.

Perché deserializzare in un oggetto dinamico?

Le impostazioni in secrets.json sono un sottoinsieme delle impostazioni di appsettings.json. Se deserializzi secrets.json in una classe che rappresenta tutte le impostazioni, finirai per sovrascrivere tutte le impostazioni.

Ecco un esempio per illustrare questo problema. Supponiamo che tu abbia la seguente classe Config:

public class Config
{
	public string Password { get; set; }
	public string Url { get; set; }
	public int Timeout { get; set; }
}
Code language: C# (cs)

E appsettings.json si presenta così:

{
  "Timeout": 5000,
  "Url": "https://localhost:12345",
  "Password": ""
}
Code language: JSON / JSON with Comments (json)

La proprietà Password viene sovrascritta in secrets.json:

{
  "Password": "hi" 
}
Code language: JSON / JSON with Comments (json)

Ora supponiamo che tu stia deserializzando secrets.json usando la classe Config:

//Load 
var secretsJson = File.ReadAllText(secretsPath);
Config secrets = JsonConvert.DeserializeObject<Config>(secretsJson);
secrets.Password = "bye";

//Save
var updatedSecretsJson = JsonConvert.SerializeObject(secrets, Formatting.Indented);
File.WriteAllText(secretsPath, updatedSecretsJson);
Code language: C# (cs)

Dai un'occhiata a secrets.json:

{
  "Password": "bye",
  "Url": null,
  "Timeout": 0
}
Code language: JSON / JSON with Comments (json)

Si noti che le proprietà Url e Timeout sono impostate sui valori predefiniti (null / 0).

Perché questo è un problema? Perché quando usi ConfigurationBuilder per caricare appsettings.json con User Secrets, sovrascriverà tutte le impostazioni definite in secrets.json:

var config = new ConfigurationBuilder()
	.SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
	.AddJsonFile("appsettings.json")
	.AddUserSecrets<Program>()
	.Build()
	.Get<Config>();

Console.WriteLine($"Url={config.Url} Timeout={config.Timeout}");
Code language: C# (cs)

Questo produce quanto segue:

Url= Timeout=0Code language: plaintext (plaintext)

Anche se le proprietà Url e Timeout hanno valori in appsettings.json, vengono sovrascritte dai valori in secrets.json. Questo mostra perché devi stare attento a cosa deserializzare secrets.json. La deserializzazione in un oggetto dinamico è l'opzione più semplice per evitare questo problema.

Nota:se non desideri utilizzare un oggetto dinamico, puoi aggiungere una classe specifica per rappresentare i valori che stai sovrascrivendo in secrets.json. Tocca a voi. Preferisco usare un oggetto dinamico.