I'm building a custom provider and would like to know how to specify a different configuration file (ex: MyProvider.Config) for my provider to pick the configuration from. By default it is using Web.Config.
Can I specify the path to the custom config file in MyProviderConfiguration class?
Example:
internal class MyProviderConfiguration : ConfigurationSection
{
[ConfigurationProperty("providers")]
public ProviderSettingsCollection Providers
{
get
{
return (ProviderSettingsCollection)base["providers"];
}
}
[ConfigurationProperty("default", DefaultValue = "TestProvider")]
public string Default
{
get
{
return (string)base["default"];
}
set
{
base["default"] = value;
}
}
}
I am not too sure what you want to do. If you just want to load up a config file from a different location you can do the following:
ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap();
configFileMap.ExeConfigFilename = "<config file path>";
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
MyProviderConfiguration customConfig = (MyProviderConfiguration)config.GetSection("
configSectionName");
If you just want to put your custom configuration inside a separate file you can do this:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="myProviderConfiguration" type="Namespace.MyProviderConfiguration, AssemblyName" />
</configSections>
<myProviderConfiguration configSource="configFile.config" />
</configuration>
And then your configFile.config file would contain:
<?xml version="1.0" encoding="utf-8"?>
<myProviderConfiguration Default="value">
<Providers>
<Provider />
</Providers>
</myProviderConfiguration>
If that doesn't help can you clarify your question further.
Related
I am trying to Deserialize XML configuration file stored in %LOCALAPPDATA%\Configuration\Configuration.XML. I want to read the key value section and store it in the local variable.
The XML file looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="FolderPath" value="C:\\Data" />
<add key="Name" value="xxx" />
<add key="Type" value="xxx" />
</appSettings>
</configuration>
ConfigurationManager.Appsettings.Get("FolderPath") does not work because the xml file is in the different location.
So I tried with the following code, which does not work.
var configFile = Path.Combine(Environment.GetEnvironmentVariable("LocalAppData"), "Configuration", "Configuration.XML")
var configuration = ConfigurationManager.OpenExeConfiguration(configFile);
var appSettings = configuration.GetSection("appSettings").SectionInformation;
Please help me to read the configuration.XML as shown above.
Thank you.
Thanks for your suggestions #jdweng.
I was able to solve the issue
var configFile = Path.Combine(Environment.GetEnvironmentVariable("LOCALAPPDATA"), "Configuration", "Configuration.XML"));
if (File.Exists(configFile))
{
ConfigurationDetails = new Dictionary<string, string>();
XDocument doc = XDocument.Load(configFile);
var elements = doc.Descendants("add");
foreach (var element in elements)
{
ConfigurationDetails.Add(element.Attribute("key").Value, element.Attribute("value").Value);
}
}
I am trying to update configuration files from other projects than the one I'm in.
The UpdateConfig() works fine, but the DeleteFromConfig() doesn't remove the entry.
Let's say I have an entry like this:
add key="someKey" value="oldValue" /
DeleteFromConfig() leaves the entry as before, but if I comment out the Remove line from UpdateConfig and try to change the value to 'newValue'it gives me this:
add key="someKey" value="oldValue,newValue" /
The AppSettings.Settings.Remove(key) line only removes the value, not the entire entry.
Is there a way to remove the whole thing?
private void UpdateConfig(string path, string key, string value)
{
Configuration config = ConfigurationManager.OpenExeConfiguration(path);
config.AppSettings.Settings.Remove(key);
config.AppSettings.Settings.Add(key, value);
config.Save(ConfigurationSaveMode.Modified);
}
private void DeleteFromConfig(string path, string key)
{
Configuration config = ConfigurationManager.OpenExeConfiguration(path);
config.AppSettings.Settings.Remove(key);
config.Save(ConfigurationSaveMode.Modified);
}
Delete the key1 from config using XmlDocument
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="key1" value="3" />
<add key="key2" value="1" />
</appSettings>
</configuration>
var xmlDoc = new XmlDocument();
xmlDoc.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
XmlNode keyNode1 = xmlDoc.SelectSingleNode("//appSettings/add[#key='key1']");
keyNode1.ParentNode.RemoveChild(keyNode1);
xmlDoc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
ConfigurationManager.RefreshSection("appSettings");
I have these pieces of code:
string theme = ConfigurationManager.AppSettings["Theme"];
private void ChangeTheme(string Name)
{
if(Name=="Light")
{
Form1.ActiveForm.BackColor = System.Drawing.Color.White;
Form.ActiveForm.ForeColor = System.Drawing.Color.Black;
}
if (Name == "Dark")
{
Form1.ActiveForm.BackColor = System.Drawing.Color.Black;
Form.ActiveForm.ForeColor = System.Drawing.Color.DarkOrange;
}
Configuration cfg = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
cfg.AppSettings.Settings["Theme"].Value = Name;
cfg.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
}
My app.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="Volume" value="7"/>
<add key="Keyval" value="X"/>
<add key="Theme" value="Light"/>
</appSettings>
</configuration>
Basically, when I press the radio buttons it changes the theme and sends the string to changetheme(), but it does not update in the app.config.
Are you running it in debug?
Probably you are looking at the wrong file. While debugging visual studio uses the config file from the bin\Debug so it would not update the App.config from the solution.
Instead of using == for comparison, I would use the String Equals Method:
Name.Equals("Light")
While I'd bet that it's not the issue, it's good practice and maybe you get lucky and that is the issue.
I have this method which populates an object from my XML "custom configuration" config file:
public static BindingList<StationConfiguration> GetStationsFromConfigFile()
{
string xmlDocumentText = File.ReadAllText(GetConfigFilePath());
var doc = new XmlDocument();
doc.LoadXml(xmlDocumentText);
BindingList<StationConfiguration> stations = new BindingList<StationConfiguration>();
foreach (XmlNode node in doc.DocumentElement["StationsSection"].ChildNodes[0].ChildNodes)
{
stations.Add(
new StationConfiguration(
node.Attributes["Comment"].Value
, node.Attributes["FtpUsername"].Value
, node.Attributes["FtpPassword"].Value
, node.Attributes["DestinationFolderPath"].Value
));
}
return stations;
}
As you can see, I'm using File.ReadAllText to pull the contents of the XML config file into a String.
This all works well for a non-encrypted config file. But now I need to encrypt it. The way MSDN suggests doing that begins like this:
System.Configuration.Configuration config =
ConfigurationManager.OpenExeConfiguration(
ConfigurationUserLevel.None);
(Incidentally, when I look at the config.FilePath property, it shows me the correct path of the XML config file, just having an extra ".config" extension for some strange reason. It ends with ".exe.config.config" for some odd reason. But I digress...)
This is my StationConfigurationSection class:
public class StationConfigurationSection : ConfigurationSection
{
[ConfigurationProperty("Stations", IsDefaultCollection = false)]
[ConfigurationCollection(typeof(StationCollection),
AddItemName = "add",
ClearItemsName = "clear",
RemoveItemName = "remove")]
public StationCollection Stations
{
get
{
return (StationCollection)base["Stations"];
}
}
public override bool IsReadOnly()
{
return false;
}
}
My complete XML config file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="StationsSection" type="EcFtpClient.StationConfigurationSection, EcFtpClient" />
</configSections>
<StationsSection>
<Stations>
<add Comment="ABC" FtpUsername="eliezer" FtpPassword="secret" DestinationFolderPath="C:\Users\eliezer\Desktop\local dest" FtpTimeoutInSeconds="30" FtpHostname="ftp://192.168.1.100/" FtpFolderPath="" />
</Stations>
</StationsSection>
<startup>
<supportedRuntime version="v2.0.50727" />
</startup>
<appSettings>
<add key="NameOfService" value="ECClient" />
<add key="PollingFrequencyInSeconds" value="60" />
</appSettings>
</configuration>
I would like to use the MSDN System.Configuration approach, since it makes en/de-cryption very easy, but how can I blend their approach with what I have to make it work?
-- UPDATE --
I've got the loading of the file but am still stuck when it comes to saving the file.I've changed the loading method (at the very top of this question) to this:
public static BindingList<StationConfiguration> GetStationsFromConfigFile()
{
Configuration config = ConfigurationManager.OpenExeConfiguration(GetConfigFilePath());
StationConfigurationSection stationsConfig = (StationConfigurationSection)config.GetSection("StationsSection");
var stationCollection = ((StationCollection)stationsConfig.Stations);
BindingList<StationConfiguration> stationsToReturn = new BindingList<StationConfiguration>();
for (int index = 0; index < stationCollection.Count; index++)
{
stationsToReturn.Add(
new StationConfiguration(
stationCollection[index].Comment,
stationCollection[index].FtpUsername,
stationCollection[index].FtpPassword,
stationCollection[index].DestinationFolderPath)
);
return stationsToReturn;
}
What that gets me is the ability to load a file regardless of whether it's encrypted or not - it loads successfully. That's great.
But I'm still not sure how to get saving working. Here's my save method:
public static void SaveStationsToConfigFile(BindingList<StationConfiguration> updatedStations, bool isConfigToBeEncrypted)
{
string configFilePath = GetConfigFilePath();
var xDoc = XDocument.Load(configFilePath);
var xDeclaration = xDoc.Declaration;
var xElement = xDoc.XPathSelectElement("//StationsSection/Stations");
// clear out existing station configurations
xDoc.Descendants("Stations").Nodes().Remove();
foreach (var station in updatedStations)
{
xElement.Add(new XElement("add",
new XAttribute("Comment", station.Station),
new XAttribute("FtpUsername", station.Username),
new XAttribute("FtpPassword", station.Password),
new XAttribute("DestinationFolderPath", station.FolderName),
new XAttribute("FtpTimeoutInSeconds", 30),
new XAttribute("FtpHostname", GetEnvironmentAppropriateFtpHostName()),
new XAttribute("FtpFolderPath", GetEnvironmentAppropriateFtpFolderPath())
));
}
xDoc.Declaration = xDeclaration;
xDoc.Save(configFilePath);
}
And in order to save it with the protection/encrpytion, I need to do something like this - in other words, using the System.Configuration.Configuration objects:
stationsConfig.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider");
stationsConfig.SectionInformation.ForceSave = true;
objConfig.Save(ConfigurationSaveMode.Modified);
But I'm currently still doing the save with XDocument.Save...
Is there a way to convert my XDocument into a System.Configuration.Configuration compatible object?The hack that comes to mind is after the call to XDocument.Save - to load it and save it again using the System.Configuration.Configuration stuff. But that's a hack...
I believe you have to play along with the configuration settings framework. Rather than trying to open the xml file yourself, you need to create a descendant of ConfigurationSection.
That way it will read and write from the encrypted configuration for you.
It looks like you already started that route (EcFtpClient.StationConfigurationSection), but you didn't include any of that code.
I need to read key values from custom sections in app/web.config.
I went through
Reading a key from the Web.Config using ConfigurationManager
and
How can I retrieve list of custom configuration sections in the .config file using C#?
However, they do not specify how to read a custom section when we need to explicitly specify the path to the configuration file (in my case, the configuration file is not in it's default location)
Example of my web.config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<MyCustomTag>
<add key="key1" value="value1" />
<add key="key2" value="value2" />
</MyCustomTag>
<system.web>
<compilation related data />
</system.web>
</configuration>
in which i need to read key value pairs inside MyCustomTag.
When i try (configFilePath is the path to my configuration file):-
var configFileMap = new ExeConfigurationFileMap { ExeConfigFilename = configFilePath };
var config =
ConfigurationManager.OpenMappedExeConfiguration(
configFileMap, ConfigurationUserLevel.None);
ConfigurationSection section = config.GetSection(sectionName);
return section[keyName].Value;
I get a error stating "Cannot access protected internal indexer 'this' here" at section[keyName]
Unfortunately, this is not as easy as it sounds. The way to solve the problem is to get file config file with ConfigurationManager and then work with the raw xml. So, I normally use the following method:
private NameValueCollection GetNameValueCollectionSection(string section, string filePath)
{
string file = filePath;
System.Xml.XmlDocument xDoc = new System.Xml.XmlDocument();
NameValueCollection nameValueColl = new NameValueCollection();
System.Configuration.ExeConfigurationFileMap map = new ExeConfigurationFileMap();
map.ExeConfigFilename = file;
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
string xml = config.GetSection(section).SectionInformation.GetRawXml();
xDoc.LoadXml(xml);
System.Xml.XmlNode xList = xDoc.ChildNodes[0];
foreach (System.Xml.XmlNode xNodo in xList)
{
nameValueColl.Add(xNodo.Attributes[0].Value, xNodo.Attributes[1].Value);
}
return nameValueColl;
}
And the call of the method:
var bla = GetNameValueCollectionSection("MyCustomTag", #".\XMLFile1.xml");
for (int i = 0; i < bla.Count; i++)
{
Console.WriteLine(bla[i] + " = " + bla.Keys[i]);
}
The result:
Formo makes it really easy, like:
dynamic config = new Configuration("customSection");
var appBuildDate = config.ApplicationBuildDate<DateTime>();
See Formo on Configuration Sections