How to create a custom app.config with just one extra entry - c#

I want my app.config file to be something like
<configSections>
<section name ="RegCompany" type =""/>
</configSections>
<RegCompany>
<Company name="Tata Motors" code="Tata"/>
<SomethingElse url="someuri"/>
</RegCompany>
Any idea how to do this? I want to get the values defined here through my code.

For simple values like this, there is an easier solution than the one in the duplicate questions.
Config:
<configSections>
<section name="RegCompany" type="System.Configuration.NameValueSectionHandler"/>
</configSections>
<RegCompany>
<add key="CompanyName" value="Tata Motors" />
<add key="CompanyCode" value="Tata" />
<add key="CompanyUrl" value="example.com" />
</RegCompany>
Code:
var section = ConfigurationManager.GetSection("RegCompany") as NameValueCollection;
if (section == null) {
throw new InvalidOperationException("Unknown company");
}
var company = section["CompanyName"];
var code = section["CompanyCode"];
var url = section["CompanyUrl"];

Related

System.InvalidOperationException : No connection string named 'db_modelContainer' could be found in the application config file

I wanted to test a method that creates an account.
public users CreateAccount(string _username, double _weight, string _password)
{
using (var db = new db_modelContainer())
{
Daily_summary summary = new Daily_summary { weight = _weight};
Users_dishes_gallery user_dishes = new Users_dishes_gallery { };
var x = db.usersSet;
foreach (var i in x)
{
if (_username == i.name)
{
throw new CreateAccountFailException("Username is already occupied!");
}
}
users newuser = new users { name = _username, weight = _weight, password = _password};
db.usersSet.Add(newuser);
db.SaveChanges();
return newuser;
}
}
I have another xUnit project where I wanted to write those tests. I prepared my first file:
[Fact]
//[AutoRollback]
public void CreateAccount_GivenNotOccupiedUsername_CreateSucceed()
{
string expectedLogin = "test";
string expectedPassword = "test";
double expectedWeight = 30;
Users user = new Users();
users createduser = user.CreateAccount(expectedLogin, expectedWeight,expectedPassword);
// Assert
Assert.Equal(expectedLogin, createduser.name);
Assert.Equal(expectedPassword, createduser.password);
Assert.Equal(expectedWeight, createduser.weight);
}
But I'm still getting that error.
error from vs
System.InvalidOperationException : No connection string named 'db_modelContainer' could be found in the application config file.
I tried many ways. Main project with edmx inside is my start project. I also added a link to App. config from my main project so my test project has access to the connection string but it didn't help me.
link to app.config
Below is my App.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<connectionStrings>
<add name="db_modelContainer" connectionString="metadata=res://*/Database.db_model.csdl|res://*/Database.db_model.ssdl|res://*/Database.db_model.msl;provider=System.Data.SqlClient;provider connection string="data source=localhost\SQLEXPRESS;initial catalog=Dietaverse_database;integrated security=True;multipleactiveresultsets=True;application name=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>
Where is your App.Config file? If it's not hosted in the same project as your Unit Test then it probably isn't being loaded into the program. Try making a copy of your App.Config file and adding it to your Unit Test project and setting the property to "Copy Always"

.NET configuration with multiple instances of a set of parameters

I have an application that can connect to several servers. The actual number of servers is not known until runtime,and may change from day to day. It takes several actual parameters to fully define a server.
I'm trying to configure the application using .NET support for application configurations.
The configuration file looks something like:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup
name="userSettings"
type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="server"
type="System.Configuration.SingleTagSectionHandler"
allowExeDefinition="MachineToLocalUser"
requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<server name="washington">
<add name="host" value="abc.presidents.com"/>
<add name="port" value="1414"/>
<add name="credentials" value="george"/>
</server>
<server name="adams">
<add name="host" value="def.presidents.com"/>
<add name="port" value="1419"/>
<add name="credentials" value="john"/>
</server>
<!--insert more server definitions here -->
</userSettings>
</configuration>
And I tried to read this with code something like this (the WriteLines are for diagnosing the problem. They will go away when/if it works.):
try
{
var exeConfiguration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
Console.WriteLine(exeConfiguration);
var userSettings = exeConfiguration.GetSectionGroup("userSettings");
Console.WriteLine("{0}: {1}", userSettings, userSettings.Name);
var sections = userSettings.Sections;
Console.WriteLine("{0}: {1}", sections, sections.Count);
foreach (ConfigurationSection section in sections)
{
Console.WriteLine("{0}", section);
// todo Here's where we capture information about a server
}
}
catch (System.Exception ex)
{
Console.WriteLine("Exception: {0}", ex.Message);
}
This throws an exception from the foreach and produces the following output:
System.Configuration.Configuration
System.Configuration.UserSettingsGroup: userSettings
System.Configuration.ConfigurationSectionCollection: 1
Exception: Sections must only appear once per config file. See the help topic <location> for exceptions.
If I remove the second server, leaving only washington, it "works" producing this output:
System.Configuration.Configuration
System.Configuration.ConfigurationSectionGroup: userSettings
System.Configuration.ConfigurationSectionCollection: 1
System.Configuration.DefaultSection
I've tried other variations on the theme (nested sectionGroups, etc.) without finding a solution. The various tutorial examples I've found seem to want me to create a separate class for each Server. This is obviously impractical, and should be unnecessary since all servers are created equal.
Questions:
Does System.Configuration support the concept of a collection of sets of related settings (like an array of structures)?
If so.. how?
If not.. is there another way to store persistent configuration information that does support this concept, or am I going to have to roll-my-own?
Progress Report
Based on the partial answer by Robert McKee I modified the xml like so:
<section name="servers"
type="System.Configuration.DefaultSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
and
<servers>
<add name="washington" host="abc.presidents.com" port="1414" credentials="george"/>
<add name="adams" host="def.presidents.com" port="1419" credentials="john"/>
<!--insert more server definitions here -->
</servers>
This is an improvement with one fatal problem. As you can see I changed the type attribute of the section element to name the class ystem.Configuration.DefaultSection DefaultSection succeeds at reading the configuration information (I think, at least it does not complain.) but it does not expose any way to access the information it read!
Therefore I need to use some other type of *Section class. Microsoft provides 95 classes derived from the ConfigurationSection base class, but all of them except DefaultSection and ClientSettingsSection appear to be targeted at special cases (urls, database connection strings, date and times, etc...) ClientSettingsSection won't even read the servers section -- complaining that <add/> is not a valid nested element.
So, bottom line is I'm going to have to write a custom ConfigurationSection to handle these settings. If I get it working I'll add an answer with the ultimate solution (unless someone provide a better answer first.)
Conclusions
Collections of property sets cannot be supported without creating custom property classes.
Support for creating custom property classes is pretty good.
Documentation for creating custom property classes is abysmal, however I did finally find a decent overview document that helped me find an answer.
The Configuration file
The app.config file I ended up with is:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings"
type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="executiveBranch"
type="PropProto.Properties.ExecutiveBranchSection, PropProto, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
allowExeDefinition="MachineToLocalUser"
requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<executiveBranch>
<presidents>
<president key="first"
name="George Washington"
legacy="The Fother of Our County"
/>
<president key="honestAbe"
name="Abraham Lincoln"
legacy="Freed the Slaves"
/>
<president key="who"
name="Chester Arthur"
/>
<president key="dubya"
name="George W. Bush"
legacy="Mission Accomplished!!!"
/>
<president key="barack"
name="Barack Obama"
legacy="Affordable Health Care"
/>
</presidents>
</executiveBranch>
</userSettings>
</configuration>
There is one more nesting level than I had expected (or want). That's because presidents is a ConfigurationElementCollection and userSettings cannot include a ConfigurationElementCollection directly, so I had to introduce executiveBranch.
Using the Configuration
The code to read these settings is:
var exeConfiguration = ConfigurationManager.OpenExeConfiguration(
ConfigurationUserLevel.PerUserRoamingAndLocal);
var userSettings = exeConfiguration.GetSectionGroup("userSettings");
var executiveBranch = (ExecutiveBranchSection)userSettings.Sections.Get(
ExecutiveBranchSection.Tag);
var presidents = executiveBranch.Presidents;
foreach (President president in presidents)
{
Console.WriteLine("{0}: {1}", president.Name, president.Legacy);
}
The Custom Properties Classes
And the custom classes to make all this work:
public class ExecutiveBranchSection : ConfigurationSection
{
public const string Tag = "executiveBranch";
[ConfigurationProperty(PresidentCollection.Tag)]
public PresidentCollection Presidents { get { return (PresidentCollection)base[PresidentCollection.Tag]; } }
}
[ConfigurationCollection(typeof(President),
CollectionType = ConfigurationElementCollectionType.BasicMap,
AddItemName = President.Tag)]
public class PresidentCollection : ConfigurationElementCollection
{
public const string Tag = "presidents";
protected override string ElementName { get { return President.Tag; } }
public President this[int index]
{
get { return (President)base.BaseGet(index); }
set
{
if (base.BaseGet(index) != null)
{
base.BaseRemoveAt(index);
}
base.BaseAdd(index, value);
}
}
new public President this[string name] { get { return (President)base.BaseGet(name); } }
protected override ConfigurationElement CreateNewElement()
{
return new President();
}
protected override object GetElementKey(ConfigurationElement element)
{
return (element as President).Key;
}
}
public class President : ConfigurationElement
{
public const string Tag = "president";
[ConfigurationProperty("key", IsRequired = true)]
public string Key { get { return (string)base["key"]; } }
[ConfigurationProperty("name", IsRequired = true)]
public string Name { get { return (string)base["name"]; } }
[ConfigurationProperty("legacy", IsRequired = false)]
public string Legacy { get { return (string)base["legacy"]; } }
}
Haven't worked with custom config sections, but from a purely logical point of view, isn't this more appropriate:
<userSettings>
<servers>
<add name="washington" host="abc.presidents.com" port="1414" credentials="george"/>
<add name="adams" host="def.presidents.com" port="1419" credentials="john"/>
<!--insert more server definitions here -->
</servers>
<!-- insert more user settings here -->
</userSettings>
You can do it other ways, but if you want a collection of "server", then it must be in a grouping element like "servers". You can't just have multiple "server" in a parent element that can also contain other types of children. The tag within the group is almost always "add".
In any case "System.Configuration.SingleTagSectionHandler" definitely is not the correct type.

Can not read Config File

I have a config file in my project, which I am not able to read in for some reason. Similar code has worked for me in the past. I am not sure what am I doing wrong here. I was wondering if someone would be able to have a look and let me know if I am doing something wrong. Please help...
Here's my code:
KeyValueConfigurationCollection settings;
Configuration config;
ExeConfigurationFileMap configFile = new ExeConfigurationFileMap();
configFile.ExeConfigFilename = "myProject.exe.config";
config = ConfigurationManager.OpenMappedExeConfiguration(configFile, ConfigurationUserLevel.None);
settings = config.AppSettings.Settings;
this.logFilePath = settings["logFilePath"].Value;
this.logFilePath = settings["logFileName"].Value;
Here's my Config File:
<?xml version="1.0"?/>
<configuration>
<add key="logFilePath" value=".//Results//" />
<add key="logFileName" value="Output.xml" />
</configuration>
Thanks in advance,
Harit
harit, try amending your structure to:
<?xml version="1.0"?/>
<configuration>
<appSettings>
<add key="logFilePath" value=".//Results//" />
<add key="logFileName" value="Output.xml" />
<appSettings>
</configuration>
Using the ConfigurationManager creates the requirement for this exact structure to be present. it should work as planned with the above change.
The AppSettings Collection is missing from your configuration. You only have the root-level of configured. But you are requesting in your code.
Your configuration should be
<configuration>
<appSettings>
<add key="logFilePath" value=".//Results//" />
<add key="logFileName" value="Output.xml" />
</appSettings>
</configuration>
Read values from different web.config:
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = AppDomain.CurrentDomain.BaseDirectory + #"second.config";
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap,ConfigurationUserLevel.None);
ConfigurationSection mySection = config.GetSection("countoffiles");
if (config.AppSettings.Settings.Count > 0)
{
System.Configuration.KeyValueConfigurationElement customSetting =
config.AppSettings.Settings["countoffiles"];
if (customSetting != null)
{
Response.Write(customSetting.Value);
}
else
{
Console.WriteLine("No countoffiles application string");
}
}

An error occurred creating the configuration section handler

I have a dot.NET 4.0 web application with a custom section defined:
<configuration>
<configSections>
<section name="registrations" type="System.Configuration.IgnoreSectionHandler, System.Configuration, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="true" restartOnExternalChanges="true" allowLocation="true"/>
....
at the end of the web.config file I have the respective section:
....
<registrations>
.....
</registrations>
</configuration>
Every time I call System.Configuration.ConfigurationManager.GetSection("registrations"); I get the following exception:
An error occurred creating the configuration section handler for registrations: The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047) (C:\...\web.config line 13)
I'm also using Unity but don't know if that's in any way related to the error.
Have you faced this error before? How can I fix it? Do I need to replace the IgnoreSectionHandler with something else?
Given this app.config:
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="registrations" type="MyApp.MyConfigurationSection, MyApp" />
</configSections>
<registrations myValue="Hello World" />
</configuration>
Then try using this:
namespace MyApp
{
class Program
{
static void Main(string[] args) {
var config = ConfigurationManager.GetSection(MyConfigurationSection.SectionName) as MyConfigurationSection ?? new MyConfigurationSection();
Console.WriteLine(config.MyValue);
Console.ReadLine();
}
}
public class MyConfigurationSection : ConfigurationSection
{
public const String SectionName = "registrations";
[ConfigurationProperty("myValue")]
public String MyValue {
get { return (String)this["myValue"]; }
set { this["myValue"] = value; }
}
}
}
You are missing the Namespace in the type attribute of your section in App.Config. Infact you dont need the full assembly info in there either. only the namespace is enough
Updated 1
yourcustomconfigclass config =(yourcustomconfigclass)System.Configuration.ConfigurationManager.GetSection(
"registrations");
and in config file only write
<section name="registrations" type="System.Configuration.IgnoreSectionHandler" requirePermission="true" restartOnExternalChanges="true" allowLocation="true"/>

ConfigurationManager.RefreshSection("appSettings") not updating config file

I am pulling my hair out with this one, having changed my app.settings url it is not reading from disk, therfore crashing my application because it is using a cached version. I have read lots of examples where it is working for people yet cant work out why this does not work
private void button1_Click(object sender, EventArgs e)
{
changeSettings();
ConfigurationManager.RefreshSection("appSettings");
this.Close();
}
public void changeSettings()
{
Configuration config =
ConfigurationManager.OpenExeConfiguration(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
KeyValueConfigurationCollection settings = config.AppSettings.Settings;
settings.Clear();
//MessageBox.Show(settings["client_postCodeRef_Service"].Value);
try
{
//settings["client_postCodeRef_Service"].Value = textBox1.Text;
//ser.Url = settings["client_postCodeRef_Service"].Value;
settings.Add("client_postCodeRef_Service", textBox1.Text);
AppSettingsSection sect = (AppSettingsSection)config.GetSection("appSettings");
ser.Url = sect.Settings["client_postCodeRef_Service"].Value;
config.Save(ConfigurationSaveMode.Modified);
MessageBox.Show(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
MessageBox.Show(settings["client_postCodeRef_Service"].Value);
}
catch (ConfigurationErrorsException e)
{
MessageBox.Show("[Exception error: {0}]",
e.ToString());
}
} // end change settings
here is my exe.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="Client.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<section name="client.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<appSettings>
<add key="client_postCodeRef_Service" value="http://127.0.0.1/directory/directory/webService.asmx"/>
</appSettings>
<system.serviceModel>
<bindings />
<client />
</system.serviceModel>
</configuration>

Categories

Resources