250 lines
7.8 KiB
C#
250 lines
7.8 KiB
C#
using System;
|
|
using System.IO;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.Configuration.Json;
|
|
using Microsoft.Extensions.FileProviders;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
namespace Umbraco.Cms.Core.Configuration
|
|
{
|
|
public class JsonConfigManipulator : IConfigManipulator
|
|
{
|
|
private static readonly object s_locker = new object();
|
|
private readonly IConfiguration _configuration;
|
|
|
|
public JsonConfigManipulator(IConfiguration configuration)
|
|
{
|
|
_configuration = configuration;
|
|
}
|
|
|
|
public string UmbracoConnectionPath { get; } = $"ConnectionStrings:{ Cms.Core.Constants.System.UmbracoConnectionName}";
|
|
public void RemoveConnectionString()
|
|
{
|
|
var provider = GetJsonConfigurationProvider(UmbracoConnectionPath);
|
|
|
|
var json = GetJson(provider);
|
|
|
|
RemoveJsonKey(json, UmbracoConnectionPath);
|
|
|
|
SaveJson(provider, json);
|
|
}
|
|
|
|
public void SaveConnectionString(string connectionString, string providerName)
|
|
{
|
|
var provider = GetJsonConfigurationProvider();
|
|
|
|
var json = GetJson(provider);
|
|
|
|
var item = GetConnectionItem(connectionString, providerName);
|
|
|
|
json.Merge(item, new JsonMergeSettings());
|
|
|
|
SaveJson(provider, json);
|
|
}
|
|
|
|
|
|
public void SaveConfigValue(string key, object value)
|
|
{
|
|
var provider = GetJsonConfigurationProvider();
|
|
|
|
var json = GetJson(provider);
|
|
|
|
JToken token = json;
|
|
foreach (var propertyName in key.Split(new[] { ':' }))
|
|
{
|
|
if (token is null) break;
|
|
token = CaseSelectPropertyValues(token, propertyName);
|
|
}
|
|
|
|
if (token is null) return;
|
|
|
|
var writer = new JTokenWriter();
|
|
writer.WriteValue(value);
|
|
|
|
token.Replace(writer.Token);
|
|
|
|
SaveJson(provider, json);
|
|
|
|
}
|
|
|
|
public void SaveDisableRedirectUrlTracking(bool disable)
|
|
{
|
|
var provider = GetJsonConfigurationProvider();
|
|
|
|
var json = GetJson(provider);
|
|
|
|
var item = GetDisableRedirectUrlItem(disable.ToString().ToLowerInvariant());
|
|
|
|
json.Merge(item, new JsonMergeSettings());
|
|
|
|
SaveJson(provider, json);
|
|
}
|
|
|
|
public void SetGlobalId(string id)
|
|
{
|
|
var provider = GetJsonConfigurationProvider();
|
|
|
|
var json = GetJson(provider);
|
|
|
|
var item = GetGlobalIdItem(id);
|
|
|
|
json.Merge(item, new JsonMergeSettings());
|
|
|
|
SaveJson(provider, json);
|
|
}
|
|
|
|
private object GetGlobalIdItem(string id)
|
|
{
|
|
JTokenWriter writer = new JTokenWriter();
|
|
|
|
writer.WriteStartObject();
|
|
writer.WritePropertyName("Umbraco");
|
|
writer.WriteStartObject();
|
|
writer.WritePropertyName("CMS");
|
|
writer.WriteStartObject();
|
|
writer.WritePropertyName("Global");
|
|
writer.WriteStartObject();
|
|
writer.WritePropertyName("Id");
|
|
writer.WriteValue(id);
|
|
writer.WriteEndObject();
|
|
writer.WriteEndObject();
|
|
writer.WriteEndObject();
|
|
writer.WriteEndObject();
|
|
|
|
return writer.Token;
|
|
}
|
|
|
|
private JToken GetDisableRedirectUrlItem(string value)
|
|
{
|
|
JTokenWriter writer = new JTokenWriter();
|
|
|
|
writer.WriteStartObject();
|
|
writer.WritePropertyName("Umbraco");
|
|
writer.WriteStartObject();
|
|
writer.WritePropertyName("CMS");
|
|
writer.WriteStartObject();
|
|
writer.WritePropertyName("WebRouting");
|
|
writer.WriteStartObject();
|
|
writer.WritePropertyName("DisableRedirectUrlTracking");
|
|
writer.WriteValue(value);
|
|
writer.WriteEndObject();
|
|
writer.WriteEndObject();
|
|
writer.WriteEndObject();
|
|
writer.WriteEndObject();
|
|
|
|
return writer.Token;
|
|
}
|
|
|
|
private JToken GetConnectionItem(string connectionString, string providerName)
|
|
{
|
|
JTokenWriter writer = new JTokenWriter();
|
|
|
|
writer.WriteStartObject();
|
|
writer.WritePropertyName("ConnectionStrings");
|
|
writer.WriteStartObject();
|
|
writer.WritePropertyName(Cms.Core.Constants.System.UmbracoConnectionName);
|
|
writer.WriteValue(connectionString);
|
|
writer.WriteEndObject();
|
|
writer.WriteEndObject();
|
|
|
|
return writer.Token;
|
|
}
|
|
|
|
private static void RemoveJsonKey(JObject json, string key)
|
|
{
|
|
JToken token = json;
|
|
foreach (var propertyName in key.Split(new[] { ':' }))
|
|
{
|
|
token = CaseSelectPropertyValues(token, propertyName);
|
|
}
|
|
|
|
token?.Parent?.Remove();
|
|
}
|
|
|
|
|
|
|
|
private static void SaveJson(JsonConfigurationProvider provider, JObject json)
|
|
{
|
|
lock (s_locker)
|
|
{
|
|
if (provider.Source.FileProvider is PhysicalFileProvider physicalFileProvider)
|
|
{
|
|
var jsonFilePath = Path.Combine(physicalFileProvider.Root, provider.Source.Path);
|
|
|
|
using (var sw = new StreamWriter(jsonFilePath, false))
|
|
using (var jsonTextWriter = new JsonTextWriter(sw)
|
|
{
|
|
Formatting = Formatting.Indented,
|
|
})
|
|
{
|
|
json?.WriteTo(jsonTextWriter);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static JObject GetJson(JsonConfigurationProvider provider)
|
|
{
|
|
if (provider.Source.FileProvider is PhysicalFileProvider physicalFileProvider)
|
|
{
|
|
var jsonFilePath = Path.Combine(physicalFileProvider.Root, provider.Source.Path);
|
|
|
|
var serializer = new JsonSerializer();
|
|
using (var sr = new StreamReader(jsonFilePath))
|
|
using (var jsonTextReader = new JsonTextReader(sr))
|
|
{
|
|
return serializer.Deserialize<JObject>(jsonTextReader);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
|
|
|
|
private JsonConfigurationProvider GetJsonConfigurationProvider(string requiredKey = null)
|
|
{
|
|
if (_configuration is IConfigurationRoot configurationRoot)
|
|
{
|
|
foreach (var provider in configurationRoot.Providers)
|
|
{
|
|
if (provider is JsonConfigurationProvider jsonConfigurationProvider)
|
|
{
|
|
if (requiredKey is null || provider.TryGet(requiredKey, out _))
|
|
{
|
|
return jsonConfigurationProvider;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
throw new InvalidOperationException("Could not find a writable json config source");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the property value when case insensative
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This method is required because keys are case insensative in IConfiguration.
|
|
/// JObject[..] do not support case insensative and JObject.Property(...) do not return a new JObject.
|
|
/// </remarks>
|
|
private static JToken CaseSelectPropertyValues(JToken token, string name)
|
|
{
|
|
if (token is JObject obj)
|
|
{
|
|
|
|
foreach (var property in obj.Properties())
|
|
{
|
|
if (name is null)
|
|
return property.Value;
|
|
if (string.Equals(property.Name, name, StringComparison.OrdinalIgnoreCase))
|
|
return property.Value;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
}
|
|
}
|