Repeating Configuration across Referenced Assemblies - c#

Let's say we have Assembly1 and Assembly2.
Assembly2 is a C# class library used by Assembly1.
Web and Service References are configured and stored in Asembly2/app.Config.
Moreover, the EF connection string(s) are in Assembly2/app.Config.
When I use Assembly2 in Assembly1, the Assembly2 config file is not used. In fact, in that scenario, only the Assembly1 configuration appears accessible through default means.
As a result, I have to copy the Assembly2 config contents into the Assembly1 config.
This has worked for me for many projects.
Is there another way? A better way?
It seems wrong to have repeating configuration data.
Do you have a recommendation or technique that works?
Thank you.

You need to apply changes to the config file of entry point exe assembly. Class library assembly (dll) config files are never used. They are made by Visual Studio so you could easily copy the settings to exe config files if needed.
Bellow is example of the config file for exe assembly that has both, settings from class library ClassLibrary1 and settings from the exe assembly MainAssembly. You can see that both connection strings are in one connectionStrings settings. However, if you need to set other settings, beside connection string, you need to add extra section.
If you are already using this technique, this is correct way to go. This technique is flexible. For example if you have more than one project having the same connection strings on one box, you could specify the connection strings in machine.config file. You can also override the settings in some projects if needed.
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings"
type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<!--This section declaratrion pasted here from dll conifg file -->
<section name="ClassLibrary1.Properties.Settings"
type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
requirePermission="false" />
<!--This section declaratrion was here in the first place -->
<section name="MainAssembly.Properties.Settings"
type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
requirePermission="false" />
</sectionGroup>
</configSections>
<connectionStrings>
<!--This connection string was here in the first place -->
<add name="MainAssembly.Properties.Settings.MainAssemblyConnectionString"
connectionString="MainConnectionStringValue" />
<!--This connection string pasted here from dll config file -->
<add name="ClassLibrary1.Properties.Settings.LibraryConnectionString"
connectionString="LibraryConnectionStringValue"
providerName="" />
</connectionStrings>
<applicationSettings>
<!--This settings section pasted here from dll config file -->
<ClassLibrary1.Properties.Settings>
<setting name="LibrarySetting"
serializeAs="String">
<value>LibrarySettingValue</value>
</setting>
</ClassLibrary1.Properties.Settings>
<!--This strings section was here in the first place -->
<MainAssembly.Properties.Settings>
<setting name="MainAssemblySetting"
serializeAs="String">
<value>MainSettingValue</value>
</setting>
</MainAssembly.Properties.Settings>
</applicationSettings>
</configuration>

A DLL (or another referenced assembly) is not meant to carry it's own app.config, but rather have everything configured by the caller. So everything should go into the app.config of the exe.
Consider for example a shared data access library that needs connection strings to the database. The library should be possible to use from a variety of applications with different connection requirements. Having the connection string tied strictly to the shared library wouldn't work, it has to be done at the client using the library.
It is possible to put systemwide settings that affect all applications running on a machine in the machine.config file, but use that approach with caution as it will affect all applications on the machine.

Related

dynamically change web service url on a windows service using app.config

In my windows service I have 2 web references
My windows service only contains an app.config not a web.config
my app config looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="MyFirstWindowsService.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<system.serviceModel>
<bindings />
<client />
</system.serviceModel>
<applicationSettings>
<MyFirstWindowsService.Properties.Settings>
<setting name="MyFirstWindowsService_postDataToMapicsWC_XAXSSTRN"
serializeAs="String">
<value>http://TESTDEV/web/services/XAXSSTRN.XAXSSTRNHttpSoap11Endpoint/</value>
</setting>
<setting name="MyFirstWindowsService_com_goodmanmfg_testdev_GETITMINFO"
serializeAs="String">
<value>http://TESTDEV/web/services/GETITMINFO.GETITMINFOHttpSoap11Endpoint/</value>
</setting>
</MyFirstWindowsService.Properties.Settings>
</applicationSettings>
</configuration>
[![enter image description here][1]][1]
the problem is my web services when i click on them the URL field is still saying
"Web reference URL" http://PROD/web/services/XAXSSTRN.XAXSSTRNHttpSoap11Endpoint
[![enter image description here][2]][2]
what is the end goal? To release this windows service to dev and prod environments without having to rebuild the entire solution.
The ideal behavior is :
Build the latest code in dev mode (test it, if all test good then , step 2)
Provide an app.config file with prod urls to dropped inside the
folder
Release
As you can see what I am trying to avoid is the need of dropping the file manually changing those 2 web services , rebuilding the solution AND THEN releasing...
Classic ASP.NET apps get their configuration from a hierarchy of web.config values. Other apps (console applications, Windows Forms apps, WPF, Services, ...) get their configuration from a configuration file named [NameOfExe].exe.config (and occasionally from [NameOfAssembly].dll.config. That file is located in the same folder as the exe itself.
For example, if your service is MyWcfService.exe, you will very likely find a MyWcfService.exe.config file in the same folder (for example, in the bin/debug folder). Its contents should be the same as your app.config.
Visual Studio makes this all "just work" by creating an app.config file in your source folder and then, at build time, copying the contents of that file to the appropriately named [NameOfExe].exe.config file in the same folder as the EXE.
In the normal case, you might have one set of URLs (and perhaps other data) for your dev environment, another for QA, another for Integration Test and another for Prod. You can manage this through the use of configuration transforms.
I think this goes some way towards answering your questions. In summary
App.config files have nearly the same capabilities as web.config
files
App.config files get "compiled" to [NameOfExe].exe.config
files at build time and placed in the same folder at the EXE
Configuration transforms may help you out with managing your URLs
Your other choice is managing a set of [NameOfExe].exe.[Environment].config files and manually putting them in the right place.

How do I make App.config values visible for referenced ClassLibraires (Assebmlies)

I have a C# Project called Application which is basically considered to represent the top most application layer. All other Layers are treated as ClassLibraries like BUSINESS, DAO and UTIL. Now I want that the application be configurable by using the App.config file. For that purpose I need to make this configuration file visible for the referenced ClassLibraries (Assemblies).
For me, the most suitable solution would be that the UTIL assembly has access to the App.config and is able to share those accessible items to the upper application layers.
So far I tried to create a Settings.settings file in the UTIL assembly which defines one item: Name: ElemName; Type: String; Scope: Application. The App.config file which is located within the Application assembly contains the following source:
<applicationSettings>
<UTIL.Settings>
<setting name="ElemName" serializesAs="String">
<value>SomeValue</value>
</setting>
</UTIL.Settings>
</applicationSettings>
If I now try to access this property via: Settings.Default.ElemName,
the build fails with error: 'UTIL.Settings' is inaccessible due to its protection level
A further approach, to make this property visible via a helper class inside assembly UTIL
public String GetElemName()
{
return Settings.Default.ElemName;
}
fails with an: 'System.Configuration.ConfigurationErrorsException' occurred in System.Configuration.dll ... Additional information: Configuration system failed to initialize
How can I get it running? (I only need to read the configuration)
The easiest is the following:
Add the required settings in the project properties of the DLL assemblies like you would do for any normal application.
Now, a DLL doesn't actually read its own app.config. The trick is to copy the entire <applicationSettings> block from the DLLs app.config to the application's app.config and also add the respective line in the <sectionGroup> section at the top of the file.
Example: Let's assume the app.config for your DLL looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="DLLSample.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<connectionStrings>
<add name="DLLSample.Properties.Settings.MyConnectionString" connectionString="Data Source=..." providerName="System.Data.SqlClient" />
</connectionStrings>
<applicationSettings>
<DLLSample.Properties.Settings>
<setting name="AllowStart" serializeAs="String">
<value>True</value>
</setting>
</DLLSample.Properties.Settings>
</applicationSettings>
</configuration>
And the app.config of your application looks like this:
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="App.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<applicationSettings>
<App.Properties.Settings>
<setting name="LogPath" serializeAs="String">
<value>C:\Temp</value>
</setting>
</App.Properties.Settings>
</applicationSettings>
</configuration>
After the above described changes, the application's config file should look like:
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="App.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<section name="DLLSample.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<connectionStrings>
<add name="DLLSample.Properties.Settings.MyConnectionString" connectionString="Data Source=..." providerName="System.Data.SqlClient" />
</connectionStrings>
<applicationSettings>
<App.Properties.Settings>
<setting name="LogPath" serializeAs="String">
<value>C:\Temp</value>
</setting>
</App.Properties.Settings>
<DLLSample.Properties.Settings>
<setting name="AllowStart" serializeAs="String">
<value>True</value>
</setting>
</DLLSample.Properties.Settings>
</applicationSettings>
</configuration>
From both your application and DLL code you'll be able to use the normal configuration settings mechanism, like access a value through Properties.Settings.Default.AllowStart from the DLL's code or Properties.Settings.Default.LogPath from the application's code.
Two things you can not do:
Access the DLL config values from your application and vice versa
Manage the DLLs config values from the application's property page. You need to edit the app.config manually to add/remove/modify settings.
Connection strings, by the way, can also be managed that way. I've added to the examples above.
I solved this issue in a different way.
The Project called Application still contains the App.config file. All referenced assemblies (Business, DAO, UTIL, and TestAssemblies) just share the applications configuration.
How to share configuration:
Project (Business, DAO, UTIL, etc.) -> Add -> Existing Item -> 'Select' App.config -> Add As Link
Project -> Add Reference -> .NET -> System.Configuration -> OK
string configValue = ConfigurationManager.AppSettings["token"];
How the App.config file looks like:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
...
<appSettings>
<add key="token" value="ConfigValue" />
</appSettings>
...
</configuration>
Without this reference to the existing App.conifg file AppSettings["token"] won't resolve the value while running with NUnit. If the application is started in debug mode, everything works fine, even without the link to App.config as mentioned by user Maarten

Overriding application settings

I have a solution which has a WinForm application (Project 1) which makes use of a Class2 from another Class Library project (Project 2). Project 2 makes use of a class3 which is defined in another Class Library project (Project 3).
I know I can override application settings of Project 2 from my Main WinForm application, but, my question is, can I override application settings which were defined in Class Library Project (Project 3) from my main WinForm application (Project 1)
I know it looks like Im making things complicated, but I had to override application settings of Project 3 from my main application.
Can anyone put some light in this direction and suggest how to resolve this?
FYI...
When you add a setting.settings file, it will automatically creates a app.config file and we can configure applicationSettings from Setting.settings UI in VS. Below is the app.config file content from Project3 whose applicationSettings Im interested to override in another WinForm project.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="Project3.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<applicationSettings>
<Project3.Settings>
<setting name="SettingInProject3" serializeAs="String">
<value>TempPath</value>
</setting>
</Project3.Settings>
</applicationSettings>
</configuration>
What modifications in app.config file of WinForm application can override the settings defined in Project3 class library.
The hierarchy of references goes something like this. WinForm>Project2DLL>Project3DLL.
Please let me know if further information is needed.
Open the settings in the source project in visual studio, Ensure the Access modifier (at the top) in the settings viewer in visual studio is set to public. Now these settings will be accessible from your external projects.

reading from app.config file

I am trying to read StartingMonthColumn and CategoryHeadingColumn
from the below app.config file using the code
ConfigurationSettings.AppSettings["StartingMonthColumn"]
but it is returning null, also ConfigurationSettings.AppSettings.Count returns zero
Please help me to read this in my windows application
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="CTARepository.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<CTARepository.Properties.Settings>
<setting name="Setting" serializeAs="String">
<value />
</setting>
</CTARepository.Properties.Settings>
</userSettings>
<appSettings>
<add key="StartingMonthColumn" value="7"/>
<add key="CategoryHeadingColumn" value="1"/>
</appSettings>
</configuration>
ConfigurationSettings.AppSettings is obsolete, you should use ConfigurationManager.AppSettings instead (you will need to add a reference to System.Configuration)
int value = Int32.Parse(ConfigurationManager.AppSettings["StartingMonthColumn"]);
If you still have problems reading in your app settings then check that your app.config file is named correctly. Specifically, it should be named according to the executing assembly i.e. MyApp.exe.config, and should reside in the same directory as MyApp.exe.
Just for the future reference, you just need to add System.Configuration to your references library:
ConfigurationSettings.AppSettings is deprecated, see here:
http://msdn.microsoft.com/en-us/library/system.configuration.configurationsettings.appsettings.aspx
That said, it should still work.
Just a suggestion, but have you confirmed that your application configuration is the one your executable is using?
Try attaching a debugger and checking the following value:
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
And then opening the configuration file and verifying the section is there as you expected.
Try:
string value = ConfigurationManager.AppSettings[key];
For more details check:
Reading Keys from App.Config
The reason is simple, your call to ConfigurationSettings.AppSettings is not returning the required config file. Please try any of the following ways:
Make sure your app config has the same name as your application's exe file - with the extension .config appended eg MyApp.exe.config
OR you can use ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location).AppSettings["StartingMonthColumn"]
Hope this helps
This:
Console.WriteLine( "StartingMonthColumn is {0}", ConfigurationManager.AppSettings["StartingMonthColumn"]);
works fine for me.
Note that ConfigurationManager is in the System.Configuration namespace (so you'll likely want a using System.Configuration; statement), and that since what you read in has a string type you'll need to parse what you read in to use it as a number.
Also, be sure you set system.configuration.dll as a reference in your project or build script.
Try to rebuild your project - It copies the content of App.config to
"<YourProjectName.exe>.config" in the build library.
Also add the key "StartingMonthColumn" in App.config that you run application from, for example in the App.config of the test project.

How do I reference configuration information from within multiple class libraries?

I've got a bunch of DLL projects that I'm pulling into my application, each contains their own Settings.settings/app.config. When I compile the app and run for debugging, everything works just fine, but come deployment time I can't get my DLLs to read their own settings files.
I've been doing some reading and it has become apparent that there's a couple of methods to getting each dll to read its own configuration - one is to dedicate a .dll.config to the library and the other is to embed the dll's configuration in the process.exe.config.
I'm having significant issues trying to implement either and I wondered if anyone has any good docs on this - there appears to be a shortage on the Net.
I'd like a separate .dll.config for each of the libraries if possible, but in a pinch, getting each of my libraries to read their own section of the process.exe.config will do.
Can anyone point me in the right direction because I'm so close to rolling this application out but this stumbling block is causing me a significant headache.
Edit: When I merge the configuration files, I start getting TypeInitializer exceptions when I initialize objects withing my libraries. This is likely just me being retarded, but does someone have a working example of a merged config file and some basic demonstrative code for reading it from multiple assemblies?
What are the "significant issues" you encountered? I started with embedding the dll's config in the exe's config, which worked, but was cumbersome. I now have all the config stuff in one dll project. The only thing I needed to do to make that work (besides copying the settings over) was to change the Settings class to be public.
Here's an example of a merged app.config that works:
<?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="SharedConfig.Client.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<!-- Begin copy from library app.config -->
<section name="SharedConfig.Library.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<!-- End copy from library app.config -->
</sectionGroup>
</configSections>
<applicationSettings>
<SharedConfig.Client.Properties.Settings>
<setting name="Bar" serializeAs="String">
<value>BarFromClient</value>
</setting>
</SharedConfig.Client.Properties.Settings>
<!-- Begin copy from library app.config -->
<SharedConfig.Library.Properties.Settings>
<setting name="Bar" serializeAs="String">
<value>BarFromLibrary</value>
</setting>
</SharedConfig.Library.Properties.Settings>
<!-- End copy from library app.config -->
</applicationSettings>
</configuration>
Have each class library define configuration settings in a custom ConfigurationSection.
Then add custom section handlers to your process.exe.config file.
This MSDN article is pretty comprehensive in its explanation, with examples in both VB and C#.
See If app.config for a DLL should be in the "main config"… what do we do with WCF References in DLLs?. The real answer is "copy and paste". That's unfortunately the general solution Microsoft had in mind. In some cases, the .NET 2.0 Settings mechanism can be used, as it bakes the default values into the DLL itself. At runtime, the DLL can then save updated settings - into the .exe.config.

Categories