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.
Related
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've created a static class to use my configurations, but when I try to add the JSON file to the configuration I got an exception:
MyConfigurations.json:
{ "ConnectionString": "my connection string", ...}
My static class constructor:
static MyConfigurations() {
var configuration = new Configuration()
.AddJsonFile("MyConfigurations.json")
.AddEnvironmentVariables();
...
...
My exception occurs when the .AddJsonFile is executed.
Exception: Object reference not set to an instance of an object."
StackTrace:
at
Microsoft.Framework.ConfigurationModel.PathResolver.get_ApplicationBaseDirectory()
at
Microsoft.Framework.ConfigurationModel.JsonConfigurationExtension.AddJsonFile(IConfigurationSourceRoot
configuration, String path, Boolean optional) at
Microsoft.Framework.ConfigurationModel.JsonConfigurationExtension.AddJsonFile(IConfigurationSourceRoot
configuration, String path) at
Project.SharedKernel.MyConfigurations..cctor() in
C:\Project\Project.SharedKernel\MyConfigurations.cs:line 86
You have not set the application base path which the configuration API needs to determine where the physical config files live. You can set it using the SetBasePath extension method. A typical implementation looks like this:
public Startup(IApplicationEnvironment appEnv)
{
var configuration = new ConfigurationBuilder()
.SetBasePath(appEnv.ApplicationBasePath)
.AddJsonFile("MyConfigurations.json")
.AddEnvironmentVariables()
.Build();
}
Note: this only counts for beta8, see this question. You don't have to specify the default base path anymore in RC1: https://github.com/aspnet/Announcements/issues/88.
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);
I am getting an InvalidArgumentException when I run my application. I am attempting to create a new ExeConfigurationFileMap, and then load it with ConfigurationManager.
public static ExeConfigurationFileMap configFile = new ExeConfigurationFileMap(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\QuikSnap\\QuikSnap.config");
public static Configuration config = ConfigurationManager.OpenMappedExeConfiguration(Settings.configFile, ConfigurationUserLevel.None);
I have also attempted to set the configuration file after declaring it, but still didn't have any luck.
If I attempt to continue after this exception, I next receive a TypeInitalizationException upon trying to set a variable to one of the values in the configuration file.
Ran into this same problem. For some ridiculous reason, initializing ExeConfigurationFileMap even with the filepath does not set the property ExeConfigFilename which is required by the Configuration objects constructor. I fixed it by immediately setting that property after instantiating the ExeConfigurationFileMap object like below:
public static ExeConfigurationFileMap configFile = new ExeConfigurationFileMap(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\QuikSnap\\QuikSnap.config");
configFile.ExeConfigFilename = "QuikSnap.config";
public static Configuration config = ConfigurationManager.OpenMappedExeConfiguration(Settings.configFile, ConfigurationUserLevel.None);
You didn't set the right property with the value of the config file path.
Also, you have a static variable dependency on another static variable in the same class. There could be potentially an issue of order of execution here (though i'm not sure)
Try this instead:
public static Configuration config = ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap()
{
ExeConfigFilename = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\QuikSnap\\QuikSnap.config"
}, ConfigurationUserLevel.None);
<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;
}