using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using CTA.Rules.Config;
using CTA.Rules.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace CTA.Rules.Actions
{
public class ConfigMigrate
{
private const string ConfigFoundMessage = "Found and migrated settings from web.config";
private readonly string _projectDir;
private readonly ProjectType _projectType;
private bool _hasData;
///
/// If connection string is encrypted, "configProtectionProvider" is present.
///
private const string providerForEncryptedConnString = "configProtectionProvider";
public ConfigMigrate(string projectDir, ProjectType projectType)
{
_projectDir = Directory.GetParent(projectDir).FullName;
_projectType = projectType;
_hasData = false;
}
public string WebformsWebConfigMigrateHelper()
{
Configuration configXml = LoadWebConfig(_projectDir);
var templateContent = TemplateHelper.GetTemplateFileContent(string.Empty, ProjectType.WebClassLibrary, Constants.AppSettingsJson);;
JObject config = ProcessWebConfig(configXml, templateContent);
return config.ToString();
}
public string Run()
{
return MigrateWebConfig();
}
///
/// Migrates the web.config file, if it exists
///
private string MigrateWebConfig()
{
var migrateConfigMessage = string.Empty;
var configXml = LoadWebConfig(_projectDir);
if (configXml == null) { return migrateConfigMessage; }
var config = ProcessWebConfig(configXml, TemplateHelper.GetTemplateFileContent(string.Empty, _projectType, Constants.AppSettingsJson));
if (_hasData)
{
migrateConfigMessage = ConfigFoundMessage;
AddAppSettingsJsonFile(config, _projectDir);
}
if (_projectType == ProjectType.Mvc || _projectType == ProjectType.WebApi)
{
// port server configuration
PortServerConfig(configXml, _projectDir, _projectType);
}
return migrateConfigMessage;
}
private void PortServerConfig(Configuration configXml, string projectDir, ProjectType projectType)
{
ConfigurationSection serverConfig = configXml.Sections[Constants.WebServer];
if (serverConfig != null)
{
ServerConfigMigrate serverConfigMigrate = new ServerConfigMigrate(projectDir, projectType);
serverConfigMigrate.PortServerConfiguration(serverConfig);
}
return;
}
private Configuration LoadWebConfig(string projectDir)
{
string webConfigFilePath = Path.Combine(projectDir, Constants.WebConfig);
if (File.Exists(webConfigFilePath))
{
try
{
XElement webConfigXml = XElement.Load(webConfigFilePath);
System.Xml.XmlDocument xmlDocument = new System.Xml.XmlDocument();
xmlDocument.Load(webConfigFilePath);
// Comment out connection strings if type has a configProtectionProvider
// This can comment out connection strings that do not have "EncryptedData"
IEnumerable encryptedConnectionStringElement =
from element in webConfigXml.Elements("connectionStrings")
where (string)element.Attribute("configProtectionProvider") != null
select element;
if (encryptedConnectionStringElement.HasAny())
{
System.Xml.XmlNode elementToComment = xmlDocument.SelectSingleNode("/configuration/connectionStrings");
string commentContents = elementToComment.OuterXml;
// Its contents are the XML content of target node
System.Xml.XmlComment commentNode = xmlDocument.CreateComment(commentContents);
// Get a reference to the parent of the target node
System.Xml.XmlNode parentNode = elementToComment.ParentNode;
// Replace the target node with the comment
parentNode.ReplaceChild(commentNode, elementToComment);
xmlDocument.Save(webConfigFilePath);
}
var fileMap = new ExeConfigurationFileMap() { ExeConfigFilename = webConfigFilePath };
var configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
return configuration;
}
catch (Exception ex)
{
LogHelper.LogError(ex, string.Format("Error processing web.config file {0}", webConfigFilePath));
}
}
return null;
}
///
/// Reads data from web.config and writes any relevant entries to appsettings.json file
///
/// The XML representation of the web.config file
/// A JSON object representing the appSettings.json file
private JObject ProcessWebConfig(Configuration webConfig, string templateContent)
{
JObject defaultContent = JsonConvert.DeserializeObject(templateContent);
var connectionStringsObjects = GetConnectionStrings(webConfig);
var appSettingsObjects = GetAppSettingObjects(webConfig);
var kestrelHttpConfig = ServerConfigTemplates.DefaultKestrelHttpConfig;
if(!string.IsNullOrEmpty(kestrelHttpConfig))
{
var kestrelConfigJobj = JObject.Parse(kestrelHttpConfig);
defaultContent.Add(Constants.Kestrel, kestrelConfigJobj);
}
_hasData = connectionStringsObjects.Any() || appSettingsObjects.Any();
if (_hasData)
{
if (connectionStringsObjects.Count > 0)
{
AddToJsonObject(defaultContent, Constants.ConnectionStrings, connectionStringsObjects);
}
if (appSettingsObjects.Count > 0)
{
AddToJsonObject(defaultContent, Constants.AppSettings, appSettingsObjects);
}
}
return defaultContent;
}
///
/// Gets connection strings from web.config file
///
///
///
private Dictionary GetConnectionStrings(Configuration webConfig)
{
Dictionary connectionStringObjects = new Dictionary();
var connectionStrings = webConfig.ConnectionStrings?.ConnectionStrings;
if (connectionStrings != null)
{
foreach (ConnectionStringSettings connectionString in connectionStrings)
{
connectionStringObjects.Add(connectionString.Name, connectionString.ConnectionString);
}
}
return connectionStringObjects;
}
///
/// Gets app settings from web.config file
///
///
///
private Dictionary GetAppSettingObjects(Configuration webConfig)
{
Dictionary appSettingsObjects = new Dictionary();
var appSettings = webConfig.AppSettings?.Settings;
if (appSettings != null)
{
foreach (KeyValueConfigurationElement appSetting in appSettings)
{
if (!Constants.appSettingsExclusions.Contains(appSetting.Key))
{
appSettingsObjects.Add(appSetting.Key, appSetting.Value);
}
}
}
return appSettingsObjects;
}
///
/// Adds data to json object
///
/// The object to add data to
/// The name of the new entry
/// The content of the new entry
private void AddToJsonObject(JObject jObject, string name, Dictionary arrayContent)
{
jObject.AddFirst(
new JProperty(name,
new JObject(
arrayContent.Select(c =>
(new JProperty(c.Key, c.Value)))
)));
}
///
/// Writes the appSettings.json file to the project dir
///
/// The content of the file
/// The project directory where this file will be created
private void AddAppSettingsJsonFile(JObject content, string projectDir)
{
File.WriteAllText(Path.Combine(projectDir, Constants.AppSettingsJson), content.ToString());
LogChange(string.Format("Create appsettings.json file using web.config settings"));
}
private void LogChange(string message)
{
LogHelper.LogInformation(message);
}
}
}