Infosys Microsoft Alliance and Solutions blog

« Chris Brumme's weblog | Main | BizTalk 2006 - 2004 Performance Comparison »

Settings in .net Fwk 2.0

Working with Configuration files in .net fwk 1.1 was additionally supported by the Configuration block available as part of Enterprise Library (EL). With the release of .net fwk 2.0 and the introduction of System.Configuration subsystem, this is now becoming the way to work with configuration files. Hence EL 2.0 doesn't include a new Configuration block any more. Check this.

Working with System.Configuration via the Settings is quite simple with Visual Studio (VS) 2005. Check this article in case you need to know how to go about using it.

What I am going to talk about here is more in terms of how to bring in settings from libraries that you use in your code and merge with main application settings. Needless to say that any application one writes, will be using quite a few library components and without properly integrating their settings with the main application, things won't work as expected at runtime.

Lets build a sample application so as to help explain things properly. From VS2005, create a new Windows Application project. I called it SettingsDemo. Then I added another project to this same solution. The type of this was Class Library project and I called it CustomLibrary. Following this I added reference to the CustomLibrary project in my SettingsDemo project so that I could start using the library component. Adding project reference ensures build dependency and hence is better than directly adding reference to CustomLibrary.dll.

You will notice that the CustomLibrary component doesn't has a settings file under Properties. You can add one by either doing a "Add New Item" and select Settings file OR, you can go to Project properties and select Settings tab. It will prompt you to create a new settings file.

Once done, you can double click Settings.settings from Solution explorer, if not already open and start adding your own configuration values. For simplicity sake, I added two entries here String1 and String2 with Application scope and gave them some default values. I then added two public methods to the CustomControl to return the strings I just added. Sample code is as below

public string FirstMessage
{
    get { return Settings.Default.String1; }
}

In order to use Settings in code, you will have to add using CustomLibrary.Properties; to the top. Go ahead and build the solution. Next I added two buttons on the Form1 in the SettingsDemo windows application project. In the Click event handlers for these buttons, I instantiated the CustomLibrary component and make a call to the public method. Sample code is as below

private void button1_Click(object sender, EventArgs e)
{
    CustomLibrary.MyClass obj = new CustomLibrary.MyClass();
    MessageBox.Show(obj.FirstMessage);
}

If you have been implementing alongside, you can build now and run the application. On the form that comes up, hit a button and you will see a message box display the string value added to the Settings.settings of CustomLibrary previously. So far so good, but the point of using Setting is the ability to change at run time. These values are expected to be part of the configuration file. However if you were to check the SettingsDemo\bin\debug folder, you won't find any.

If you have been implementing alongside, you can build now and run the application. On the form that comes up, hit a button and you will see a message box display the string value added to the of previously. So far so good, but the point of using Setting is the ability to change at run time. These values are expected to be part of the configuration file. However if you were to check the folder, you won't find any.

So how did the code work? If you would go back to the solution explorer and navigate to Settings.designer.cs in the CustomLibrary project, and open it, you will notice that this file has two public methods and their names are same as the names we used in the Settings. Incidently, this is also the reason why we were able to access these via the Settings.Default.String1; call shown earlier. You will also notice that there is DefaultSettingValueAttribute and it has the value we entered for the setting in question earlier. The code (snapshot) in Settings.designer.cs would look something like below

[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()][global::System.Configuration.DefaultSettingValueAttribute("This is string1")]
public string String1 {
    get {
        return ((string)(this["String1"]));
    }
}

The ApplicationScopedSettingAttribute was added since we marked the setting as Application scope. If it is user scope, the attribute used will be UserScopedSettingAttribute. The DebuggerNonUserCodeAttribute is to mark this code as non-user code. In this case, this is wizard generated code. The final one DefaultSettingValueAttribute is the one that ensures that even when there isn't a configuration file present, there will still be a default value returned and prevent exceptions during code execution.

The was added since we marked the setting as Application scope. If it is user scope, the attribute used will be . The is to mark this code as non-user code. In this case, this is wizard generated code. The final one is the one that ensures that even when there isn't a configuration file present, there will still be a default value returned and prevent exceptions during code execution.

If you are wondering that how do I change these values at runtime, since I can't be expected to edit this Settings.designer.cs file and rebuild everytime, you need to check out the app.config file in CustomLibrary project. This is where the entries are added and it is this file that you will modify at runtime to get the new values for your configurations. In my case the app.config file looks like below

<?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="CustomLibrary.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    </sectionGroup>
  </configSections>
  <applicationSettings>
    <CustomLibrary.Properties.Settings>
      <setting name="String1" serializeAs="String">
        <value>This is string1</value>
      </setting>
      <setting name="String2" serializeAs="String">
        <value>This is string2</value>
      </setting>
    </CustomLibrary.Properties.Settings>
  </applicationSettings>
</configuration>

When you build, you will also see CustomLibrary.dll.config getting created in CustomLibrary\bin\Debug folder. However this isn't copied to the SettingsDemo\bin\Debug folder and hence you aren't able to change the values at runtime. However don't get carried way and copy this file to SettingsDemo\bin\Debug for that doesn't help. You can give it a quick try. Copy the CustomLibrary.dll.config to this folder, edit it and make changes to the value of String1 or String2 setting and re-run the application. It will continue to show the old values.

This is where the merging comes into picture and for this we need to access the app.config file for SettingsDemo application. In case you don't see this file in solution explorer, you can add a new one via "Add New Item" and select Application Configuration file. It is in this file that we need to copy the entries done in app.config of CustomLibrary component. To easily follow how to make these entries, let first add a Setting to SettingsDemo project also. This will ensure that we already have entries in the App.config file for SettingsDemo project. I added a new setting called LocalString.

To this file we will add the CustomLibrary settings also. If you see the App.config file, you will see the <applicationSettings> section. It is in this section that the settings from CustomLibrary will be copied. You will also notice a subgroup <SettingsDemo.Properties.Settings> and likewise we will copy the entire section from CustomLibrary's app.config file to this. Additionally, to be able to read this newely added section, we need to make an entry to the <configSections><sectionGroup> group. Currently it is having an entry like <section name="SettingsDemo.Properties.Settings" ... and we need to add CustomLibrary.Properties.Settings. After modifications the file will look like as below (the bold faced text shows the additions done)

<?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="SettingsDemo.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
      <section name="CustomLibrary.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    </sectionGroup>
  </configSections>
  <applicationSettings>
    <SettingsDemo.Properties.Settings>
      <setting name="LocalString" serializeAs="String">
        <value>This is local string</value>
      </setting>
    </SettingsDemo.Properties.Settings>
    <CustomLibrary.Properties.Settings>
      <setting name="String1" serializeAs="String"
>
        <value>This is string1</value
>
      </setting
>
      <setting name="String2" serializeAs="String"
>
        <value>This is string2</value
>
      </setting
>
    </CustomLibrary.Properties.Settings
>
  </applicationSettings>
</configuration>

With this, now buid the application. Go to the SettingsDemo\bin\debug folder and open and edit the SettingsDemo.exe.config to make changes to the values of individual settings. Save and close the file and then run the SettingsDemo.exe from this folder. When you invoke the buttons, you will see the new values being displayed.

With this, now buid the application. Go to the folder and open and edit the to make changes to the values of individual settings. Save and close the file and then run the from this folder. When you invoke the buttons, you will see the new values being displayed.

Note that after making changes to the SettingsDemo.exe.config, if you run from VS, it might end up overwritting your modified file, so it is best to directly run the EXE as I mentioned above.

Hope this helps. Get back to me in case of any questions.

Comments

Great article Atul!

@Rick, thanks for the appreciation. I have been away for a while so didn't check the comments earlier.

Hi Atul, nicely done. Do you have this application for download at some place?

Thanks.

@Nilesh, I had the code, but don't have it right now. If you follow thro' you would be able to get this done. If you get stuck, feel free to write back to me

Atul, I have a question. If SettingsDemo isn't .NET-application, but my CustomLibrary.dll is .NET assembly, what should I do in this case? How can I use CustomLibrary.dll application-scoped settings?
Thanks

Maxim: Are you saying that you have a .net assembly (dll) that you are using in a non .net application? In that case, i guess one approach would to be work with XML files directly rather than using settings.

Nicely written, and I was able to follow and use it completely with an application. However, with a web-aplication calling a dll, and the dll calling a webservce, there are some differences that I wonder if you could address.

The web.config does not have , but does have .
web.config does not appear to have either. I'll play with this as a foundation, so thank you.

Wingover: If it is a web application calling a DLL, then you need to add almost the entire config file of the DLL to web.config. You can insert this just above the node within node, as shown below


<configuration>
    <configSections>
        <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
            <section name="ClassLibrary1.Settings1" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
        </sectionGroup>
    </configSections>
    <applicationSettings>
        <ClassLibrary1.Settings1>
            <setting name="Name" serializeAs="String">
                <value>Atul Gupta</value>
            </setting>
        </ClassLibrary1.Settings1>
    </applicationSettings>
    <appSettings />
    <connectionStrings/>
    <system.web>

im new to this...

if u calling the DLL.. where should u put the DLL file?... i dont see any link to local directory/url pointing to that file?

XCD: if you can explain your scenario better I can provide some help.

However if it is a windows application, typically the DLL will go into the same folder as your EXE, unless you are creating sub-directories to keep your DLLS. In this case you need to keep the name of the sub-directory to either the same as the DLL or ensure you have probing path set correctly in configuration file, else the DLL will not load at run time.

If this is a web application, the DLL will go in the bin directory like other DLLs

Fisrt, thanks so much Atul -- I've been looking for this info for a while, and you made it quite clear.

I have a couple general questions:


what is the purpose of the app.config file in the class library? As far as I can tell, its purpose is to provide sample config code to be copied over into the application's config file. Perhaps I'm missing something ...


Our solution builds 2 web applications, a web service, and 3 windows services. These 6 applications use many of the same config settings. Right now, we copy the various settings to each app's config file; thus, we have 6 places where each setting must live. This is way ugly. Does anyone have a suggestion for dealing with this situation?


Thank-you!

Charlotte

@Charlotte, to answer your first question, you are right and that's why the solution I discussed above talks about moving the values from the class library's config file to the main app config file. People working with Settings, sometimes don't quickly realize that these actually go and reside in the config file and hence this entire discussion.

As for your second question, that is a bit more tricky and I would also like to hear what others have to say. One option could be to try the post build event in VS and work with that or use tools like NANT or MSBuild to build the solution with code to copy the config file to various directories and add applicaiton specific entries as well.

Hi,

Any way of forcing the dll to use its own config file and have the winapp use its own? Merging the contents by hand is not an option :(

Thanks!

Fantastic solution for the consumed webservice in a dll configuration management (in web.config). This is something we have spent a bit of time trying to sort out.

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

Please key in the two words you see in the box to validate your identity as an authentic user and reduce spam.

Subscribe to this blog's feed

Follow us on

Blogger Profiles

Infosys on Twitter