I am trying to read the custom-defined configuration file from the library project that I have created in c#.
To read the configuration file, There is a ConfigManager i have created as below,
static Configuration ConfigManager
{
get
{
if (_configuration == null)
{
//Map the new configuration file.
ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap();
configFileMap.ExeConfigFilename = _assemblyLocation;
// Get the mapped configuration file
_configuration = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
}
return _configuration;
}
}
I am getting the exception at OpenMappedExeConfiguration() Method.
Any help would be appreciated.
Thanks in advance.
I'm trying to save a string to the AppSettingsSection of the current application's default configuration in the roaming profile using ConfigurationManager (ConfigurationUserLevel.PerUserRoaming).
When I'm saving to the local profile (ConfigurationUserLevel.None) it works just fine.
// Write Name in NameSaved Section of AppSettings
public void WriteNameToAppSettings(string nameToSave)
{
// Open Config File
Configuration configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoaming); // ConfigurationUserLevel.None (local) is working just fine...
// Add or Update NameSaved Section of AppSettings
if ((configuration.AppSettings.Settings["NameSaved"]?.Value) == null)
configuration.AppSettings.Settings.Add("NameSaved", nameToSave);
else
configuration.AppSettings.Settings["NameSaved"].Value = nameToSave;
// Save and Refresh Config File
configuration.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection(configuration.AppSettings.SectionInformation.Name);
}
// Set LastEnteredName Property from NameSaved Section of AppSettings
public void ReadNameFromAppSettings()
{
// Read Config File and then Get Name LastEntered Section of AppSettings
LastEnteredName = ConfigurationManager.AppSettings["NameSaved"]?.ToString() ?? ""; // If null default to ""
}
The error I'm getting is:
System.InvalidOperationException: 'ConfigurationSection properties cannot be edited when locked.'
Any clues on how to fix this?
I had tried to encrypt the web config, using different ProtectionProviders but these methods will not full-fill the security.As i can decrypt the file easily from another application:
The Method i used for encryption:
public void EncryptConnString()
{
Configuration confg = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
ConfigurationSection confStrSect = confg.GetSection(section);
if (confStrSect != null)
{
confStrSect.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
confStrSect.SectionInformation.ForceSave = true;
confg.Save(ConfigurationSaveMode.Full);
}
}
If i copied the encrypted appSettings to another application and call the method for decryption. this will give the original data, If i attach the encrypted config file with any other application and call the method for decryption, it will get easily decrypted.
That means; If anyone can access the config file can easily get the
values, through decryption.
So here my question is that; How can i encrypt the web.config with a password? or else provide an application level encryption(restrict other application to decrypt the file).
The method used for decryption:
public void DecryptConnString()
{
Configuration confg = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
ConfigurationSection confStrSect = confg.GetSection(section);
if (confStrSect != null)
{
confStrSect.SectionInformation.UnprotectSection();
confStrSect.SectionInformation.ForceSave = true;
confg.Save(ConfigurationSaveMode.Full);
}
}
I had tried with the following ProtectionProviders:
MyUserDataProtectionConfigurationProvider
DataProtectionConfigurationProvider
RSAProtectedConfigurationProvider
Note: I have to do this programmatically so that aspnet_regiis will not help me
I am Trying to get the configuration file using the following code:
public void EncryptConnString()
{
Configuration config = WebConfigurationManager.OpenWebConfiguration(HttpContext.Current.Server.MapPath(#"/"));
ConfigurationSection section = config.GetSection("connectionStrings");
if (!section.SectionInformation.IsProtected)
{
config.Save(ConfigurationSaveMode.Modified);
}
}
But i am getting the error
The relative virtual path 'F:/xxxx/yyyy/sample/' is not allowed here.
Note: I am accessing this code in global.asax page What i am doing wrong?
If you pass null to this method, it will return the root config file for you:
var config = WebConfigurationManager.OpenWebConfiguration(null);
<configuration>
<configSections>
<section name="ADMIN" type="System.Configuration.DictionarySectionHandler"/>
</configSections>
<User>
<add key="ExtendTime" value="20"/>
<add key="Name" value="sss"/>
</User>
<configuration>
i have to remove first child element in user config section i.e . Reply me if you have any idea for this.
i am using
Configuration config = ConfigurationManager.OpenExeConfiguration(Context.Parameters["assemblypath"]);
ConfigurationSection section = config.GetSection("USER");
This article may have what you're looking for : http://raquila.com/software/configure-app-config-application-settings-during-msi-install/
Excerpt from article:
string exePath = string.Format("{0}MyWindowsFormsApplication.exe", targetDirectory);
Configuration config = ConfigurationManager.OpenExeConfiguration(exePath);
config.AppSettings.Settings["Param1"].Value = param1;
config.AppSettings.Settings["Param2"].Value = param2;
config.AppSettings.Settings["Param3"].Value = param3;
config.Save();
EDIT: Adding additional code sample and blog reference: http://ryanfarley.com/blog/archive/2004/07/13/879.aspx
using System;
using System.Xml;
using System.Configuration;
using System.Reflection;
//...
public class ConfigSettings
{
private ConfigSettings() {}
public static string ReadSetting(string key)
{
return ConfigurationSettings.AppSettings[key];
}
public static void WriteSetting(string key, string value)
{
// load config document for current assembly
XmlDocument doc = loadConfigDocument();
// retrieve appSettings node
XmlNode node = doc.SelectSingleNode("//appSettings");
if (node == null)
throw new InvalidOperationException("appSettings section not found in config file.");
try
{
// select the 'add' element that contains the key
XmlElement elem = (XmlElement)node.SelectSingleNode(string.Format("//add[#key='{0}']", key));
if (elem != null)
{
// add value for key
elem.SetAttribute("value", value);
}
else
{
// key was not found so create the 'add' element
// and set it's key/value attributes
elem = doc.CreateElement("add");
elem.SetAttribute("key", key);
elem.SetAttribute("value", value);
node.AppendChild(elem);
}
doc.Save(getConfigFilePath());
}
catch
{
throw;
}
}
public static void RemoveSetting(string key)
{
// load config document for current assembly
XmlDocument doc = loadConfigDocument();
// retrieve appSettings node
XmlNode node = doc.SelectSingleNode("//appSettings");
try
{
if (node == null)
throw new InvalidOperationException("appSettings section not found in config file.");
else
{
// remove 'add' element with coresponding key
node.RemoveChild(node.SelectSingleNode(string.Format("//add[#key='{0}']", key)));
doc.Save(getConfigFilePath());
}
}
catch (NullReferenceException e)
{
throw new Exception(string.Format("The key {0} does not exist.", key), e);
}
}
private static XmlDocument loadConfigDocument()
{
XmlDocument doc = null;
try
{
doc = new XmlDocument();
doc.Load(getConfigFilePath());
return doc;
}
catch (System.IO.FileNotFoundException e)
{
throw new Exception("No configuration file found.", e);
}
}
private static string getConfigFilePath()
{
return Assembly.GetExecutingAssembly().Location + ".config";
}
}
Then you would use it like this:
// read the Test1 value from the config file
string test1 = ConfigSettings.ReadSetting("Test1");
// write a new value for the Test1 setting
ConfigSettings.WriteSetting("Test1", "This is my new value");
// remove the Test1 setting from the config file
ConfigSettings.RemoveSetting("Test1");
I have come to the conclusion that it is not possible to access a custom configuration section during installation using:
MyCustomConfigurationSection section = (MyCustomConfigurationSection)config.GetSection("MyCustomConfigurationSection");
When the MSI package is installed, the program executed is the Windows Install(MsiExec), not the program which contains the installer class.
'%windir%\system32\msiexec.exe
In order to access the config we need to workaround this issue either by using the context:
Configuration config = ConfigurationManager.OpenExeConfiguration(this.Context.Parameters["assemblypath"]);
Or, by using reflection retrieve the location of the executing assembly:
Configuration config = ConfigurationManager.OpenExeConfiguration(System.Reflection.Assembly.GetExecutingAssembly().Location);
As Chuck suggested, you can access the AppSettings and modify them:
AppSettingsSection appSettings = (AppSettingsSection)config.GetSection("appSettings");
appSettings.Settings["Environment"].Value = _Environment;
config.Save();
This is fine, because the installer knows exactly how to deal with
System.Configuration.AppSettingsSection
because that library is part of .NET. However, when it comes to a custom section, the installer needs to know how to deal with that custom config. More than likely, you have it in a class library (in a DLL) that is referenced by your application and that DLL has now been installed in the install directory.
The problem is, as we know from above, MSIExec.exe isn't running in the context of that directory, so the install fails, when it can't find the appropriate DLL in system32, it throws the error:
An error occurred creating the
configuration section handler for
'XXX': Could not load file or assembly
'XXX.dll' or one of its dependencies.
The system cannot find the file
specified.
The only way therefore, to access the custom config, is to treat the config file as an XML document, and edit it using traditional XML management tools:
// load the doc
XmlDocument doc = new XmlDocument();
doc.Load(Assembly.GetExecutingAssembly().Location + ".config");
// Get the node
XmlNode node = doc.SelectSingleNode("//MyCustomConfigurationSection");
// edit node here
// ...
// Save
doc.Save(Assembly.GetExecutingAssembly().Location + ".config");
This technique is described on Ryan Farley's blog, as Chuck pointed out in the comments to his original answer.
Good news! I have found a way how to work-around this problem.
Solution is to intercept loading of assembly and return one we have. To do so
ResolveEventHandler handler = new ResolveEventHandler(CurrentDomain_AssemblyResolve);
AppDomain.CurrentDomain.AssemblyResolve += handler;
try
{
section = config.GetSection("mySection") as MySection;
}
catch(Exception)
{
}
AppDomain.CurrentDomain.AssemblyResolve -= handler;
and
Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (args.Name == "Dead.Beef.Rocks")
{
return typeof(MySection).Assembly;
}
return null;
}