.Net Configuration Editor problem - c#

I have added some settings to my c# application using the configuration editor. There are three configuration items; two of type string and one of type int. All three have Application scope.
When I compile my application the exe.config file contains two subsections under <applicationSettings>. These are <appName.Settings> containing all three configuration items and <appName.Settings1> containing only the string values.
So, instead of having the following structure
<applicationSettings>
<appName.Settings>
...
...
...
</appName.Settings>
</applicationSettings>
I have the following structure
<applicationSettings>
<appName.Settings>
...
...
...
</appName.Settings>
<appName.Settings1>
...
...
</appName.Settings1>
</applicationSettings>
I have looked at the properties and cannot see anything that looks like it could prompt this behaviour. Can anyone shed any light on why this is happening and tell me how to stop it?
Thanks.

Look near the top of the config file for:
<sectionGroup name="applicationSettings" ...
<section name="Settings" ...
<section name="Settings1" ...
</sectionGroup>
Delete the Settings1 entry, then delete the applicationSettings section for Settings1 that you mention above.
<appName.Settings1>
...
...
</appName.Settings1>
By chance did you change the name of this application or assembly after creating the 2 string settings? When the assembly name changes it creates a new applicationSettings entry, AND leaves the old assembly name settings in the config file.

Related

ConfigurationErrorException on null DateTime

I'm suddenly running into a ConfigurationErrorException for a WPF app which was running fine for a number of months (it's a task tray application).
The exception is being thrown by this auto-generated code in Settings.Designer.cs:
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public global::System.DateTime LastBackup {
get {
return ((global::System.DateTime)(this["LastBackup"]));
}
set {
this["LastBackup"] = value;
}
}
When the app first runs after being installed LastBackup is undefined/null/empty, which is what's causing the exception.
Interestingly, the auto-generated code lacks a [global::System.Configuration.DefaultSettingValueAttribute("")] attribute, which all the other auto-generated properties have.
If this was my own code it'd be easy enough to fix. But since it's generated by the Settings subsystem, any change I make would be overwritten.
There are a number of ways to work around this problem, including abandoning the built-in Settings subsystem and rolling my own configuration system. But I'm curious as to other approaches used to deal with undefined or null settings.
I was able to reproduce this error by altering App.config.
This is the default userSettings section I get when I create setting (named "Setting", sorry for the lack of imagination) in the VS Settings editor with an empty "Value" cell.
<userSettings>
<WPFTreeViewItemWrap.Properties.Settings>
<setting name="Setting" serializeAs="String">
<value />
</setting>
</WPFTreeViewItemWrap.Properties.Settings>
</userSettings>
This returns a non-null DateTime equal to {1/1/0001 12:00:00 AM}:
var x = Properties.Settings.Default.Setting;
But I get the same exception as you if I remove the empty <value /> element, like so:
<userSettings>
<WPFTreeViewItemWrap.Properties.Settings>
<setting name="Setting" serializeAs="String"></setting>
</WPFTreeViewItemWrap.Properties.Settings>
</userSettings>
System.Configuration.ConfigurationErrorsException: 'Required attribute 'value' not found.'
I would look at App.config. It may have been changed.

NUnit appSettings file attribute (linked config file) is not seen by ConfigurationManager in test

I have NUnit test (version 2.6.4) test. It uses ConfigurationManager.AppSettings["foo"] to retrive a configuration setting from the app.config file (which is in the test project). This is my App.config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings file="bar.config">
<add key="thisSettingIsVisible" value="yes, indeed"/>
</appSettings>
</configuration>
and this is bar.config file:
<appSettings>
<add key="foo" value="this setting isn't visible"/>
</appSettings>
I'm using ReSharper 10 test runner to execute the test. bar.config file is copied to the bin/Debug directory. In fact, that configuration was working some time ago, but stopped. Any clues what can be wrong?
Now, I've figured out a workaround, but I'm not happy with this solution:
private static void InitializeAppSettings()
{
var exeAssembly = System.Reflection.Assembly.GetExecutingAssembly();
var assemblyName = exeAssembly.GetName().Name + ".dll";
var testDllFolder = new Uri(System.IO.Path.GetDirectoryName(exeAssembly.CodeBase)).LocalPath;
var openExeConfiguration = ConfigurationManager.OpenExeConfiguration(Path.Combine(testDllFolder, assemblyName));
foreach (var setting in openExeConfiguration.AppSettings.Settings.AllKeys)
{
ConfigurationManager.AppSettings[setting] = openExeConfiguration.AppSettings.Settings[setting].Value;
}
}
BTW. I can't abstract away ConfigurationManager usage form existing, legacy code.
I replicated your use case and found that my additional config worked in the context of an ASP.NET site but the additional appSetting was null in a test project until I changed the Copy to Output Directory property to Copy Always
If you use R# 10.0.0 or R# 10.0.1 - it is a known issue for such builds and it has been fixed in R# 10.0.2 build.

Replace #ifdefs in C# DLL

I have a C++ DLL which has #defines used like (these defines are automatically defined based on the build configuration, e.g. Debug, Release, etc)
#if defined(CONSTANT)
..
// Some code
#else
// Some other code
I need same functionality in C# dll.
Is it ok if I define some global constants in C# dll and use them
instead of defines?
e.g.
if(Globals.SomeConstant == SOMEVALUE)
// Do this
else
// Do smth else
Then when I want to ship the DLL I will in advance (probably as a default value during declaration) assign SOMEVALUE to Globals.SomeConstant - will this work this way? (Depending on which configuration I need).
I saw some similar questions but they weren't about DLLs.
You can use it similarly as in c++
You can define / undefine them in your source code or as a conditional compilation symbol. In visual studio this can be done using Solution Explorer - Properties - Build - conditional compilation symbols
However, nowadays people tend to use a configuration file for these constants. This way, you don't have to recompile your source code nor redistribute it to change the behaviour.
The most easy method is via visual studio solution explorer - properties - settings
You can add settings for most types. Booleans come closest to #define. Using an int can give you more than two possibilities. See the difficulties if you wanted to be able to use several values for a TimeSpan or an URI using #define.
The nice thing about using the settings is that a class is generated for you to easily access the settings.
Another method is to read the config file directly using the System.Configuration.ConfigurationManager class. This gives you more freedom about the format of the configuration. The disadvantage is that you have to convert the read values into proper types yourself, inclusive handling errors if the value can't be read.
Summarized: advantages of the config file method:
No need to change source files
No need to recompile
No need to re-install
only change the config file on those machines that need the change
improved type safety
My previous answer lead to a more questions than it answered. Hence I thought an example would help.
Suppose I have a DLL, called MyDll. It has a configuration setting that in really old times would have been defined using #define.
My C-synctax is a bit rusty, but it would look like:
#define UseAlternateGreeting
public class MyClass
{
public string GetGreeting()
{
#if defined UseAlternateGreeting
return "Hello World!";
#else
return "Here I am!";
#endif
}
}
Now suppose we have several programs that use this DLL. Program! wants to use the default setting. However Program2 wants to use the alternate setting. There is no way to solve this.
Besides if we want to change the value of the setting we have to recompile and redistribute everything to everyone.
Wouldn't it be easier if we could just edit a file with notepad to change the string?
Luckily Microsoft also saw the advantage of this. Over more than 10 years we have the idea of configuration files. Assemblies have a config file with the name of the application and the extension config. This file can easily be edited using any text editor by those who know what the configuration items mean.
If we replace the #define with an item in the config file the greeting could be changed to the alternate greeting without having to recompile and redistribute the whole program.
Luckily Visual Studio helps us a lot when creating the config file.
Preparations
Let Visual Studio Create a console application in a new Solution: name the program ConfigExample
Add a new Library to this application, name it MyDll
View the properties of MyDll
Add a Setting.
Name: MySetting,
Type: string,
Scope: application,
Value: Hello World! (without string quotes)
In project MyDll create a class MyClass
public class MyClass
{
public string GetText()
{
return Properties.Settings.Default.MySetting;
}
}
Go to project ConfigExample
Project Add reference to MyDll (via tab page solution)
Use the code in your main:
using MyDll;
static void Main(string[] args)
{
var obj = new MyClass();
var txt = obj.GetText();
Console.WriteLine(txt);
}
Compile and run, and you'll see the proper text displayed. If you go to the debug / bin directory of the program you'll find a text file ConfigExample.config. Open it in a text editor and you'll see... nothing abut hello world!
This means that your program is not really interested in a special setting, the setting that was default the time that MyDll was built may be used.
However, if you want to use a special setting,
In visual Studio, Go to project MyDll
open file app.config
a.o. you'll find the following
(to prevent the editor interfering with the formatting, I added an apostrophe to each line)
'</configSections>
'<applicationSettings>
'<MyDll.Properties.Settings>
'<setting name="MySetting" serializeAs="String">
'<value>Hello World!</value>
'</setting>
'</MyDll.Properties.Settings>
'</applicationSettings>
Copy paste this part to ConfigExample.Config
for all already distributed programs do this in the folder where the executable is (in your case: debug/bin)
for all ConfigExample programs that will be built in the future do this in visual studio in App.Config of the ConfigExample project.
The result will be as follows:
'<?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="MyDll.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
' </sectionGroup>
' </configSections>
' <applicationSettings>
' <MyDll.Properties.Settings>
' <setting name="MySetting" serializeAs="String">
' <value>Hello World!</value>
' </setting>
' </MyDll.Properties.Settings>
' </applicationSettings>
'
' <startup>
' <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
' </startup>
'</configuration>
Now all we have to do is change the Hello World into an alternat greeting
' <MyDll.Properties.Settings>
' <setting name="MySetting" serializeAs="String">
' <value>Here I am!</value>
' </setting>
' </MyDll.Properties.Settings>
Run the program without building it and you'll see that the new value is used.
Advantages:
- It works with a lot of types that can be assigned from string - Type.IsAssignableFrom(typeof(string)). Visual Studio already supports a lot of types including TimeSpan and DateTime.
- You don't have to recompile your source code to change the value
- Several executables can use their own configuration setting: one program could use the original greeting, the other can use the alternate one
- If your program doesn't provide a value in the config file the default value is used.
- You don't have to read the configuration yourself.
- It is type safe: if you say it is a TimeSpan, then you have to do some serious typing to confuse it with for example an integer.
Well there is a lot more to be said about configuration, you can even have a configuration per user. But that's far outside your question about alternatives for plain C #define

Losing precision when saving a DateTimeOffset setting in project settings

When I save a DateTimeOffest in my project settings, I'm losing some precision :
The first variable is the original value, before serialization.
The second is the value after Deserialization.
In fact my variable is serialized like this in the config file :
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<userSettings>
<MyApp.Properties.Settings>
[...]
<setting name="LatestCheckTimestamp" serializeAs="String">
<value>02/22/2013 14:39:06 +00:00</value>
</setting>
[...]
</MyApp.Properties.Settings>
</userSettings>
</configuration>
Is there a way to specify some serialization parameters to increase precision ?
I know I can use some workaround, for example by storing the Ticks and the offset value or something like that, but I d'like to know if there's not a better way.
EDIT :
More info : I'm using the standard Visual Studio project settings to store my value :
MyApp.Settings.Default.LatestCheckTimestamp = initialLatestCheckTimestamp;
MyApp.Settings.Default.Save();
MyApp.Settings is the class generated by Visual studio when you edit settings in the project properties page.
EDIT 2 : Solution :
Base on the answer of Matt Johnson, this is what I did :
Renamed the setting from LatestCheckTimestamp to LatestCheckTimestampString but not in my code
Added the following Wrapper in an independent file to complete the partial class Settings :
.
public DateTimeOffset LatestCheckTimestamp
{
get { return DateTimeOffset.Parse(LatestCheckTimestampString); }
set { LatestCheckTimestampString = value.ToString("o"); }
}
The new config file now looks like :
<configuration>
<userSettings>
<MyApp.Properties.Settings>
[...]
<setting name="LatestCheckTimestampString" serializeAs="String">
<value>2013-02-22T16:54:04.3647473+00:00</value>
</setting>
</MyApp.Properties.Settings>
</userSettings>
</configuration>
... and my code still is
MyApp.Settings.Default.LatestCheckTimestamp = initialLatestCheckTimestamp;
MyApp.Settings.Default.Save();
The most reliable way to serialize a DateTimeOffset is with the RoundTrip pattern, which is specified with the "o" standard serialization string.
This uses the ISO8601 standard, which is highly interoperable with other systems, languages, frameworks, etc. Your value would look like this: 2013-02-22T14:39:06.0000000+00:00.
.Net will store fractional seconds to 7 decimals with this format.
If you can show some code of how you are storing and retrieving your app setting, I can show you where to specify the format string. In most cases, its simply .ToString("o").

Registering generic types and services with Castle Windsor IoC

Hello again stackoverflowians,
I thought it was about time that I learnt how to use a DI framework. I've heard a lot of good things about Castle Windsor so I decided to go with that. Now there are PLENTY of tutorials out there on how to use it, however, I cannot find much useful information about what to do when Generics get involved. Here is my issue.
I have a BaseDAO
namespace Utilities.DataAccess
{
public class BaseDAO<T> : IBaseDAO<T>
{
public BaseDAO(IConnectionProvider _connectionProvider)
{
// Stuff
}
}
}
Im a little bit new to generics in this context and I have seen some tutorials which have a 'BaseDAO' with no generic declaration and simply the interface it implements with the generics on it. I have used the above way of doing things on many previous projects (without IoC) and its worked fine for me...anyways, onwards to the App.config !
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section
name="castle"
type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"></section>
</configSections>
<castle>
<components>
<component
id="BaseDAO"
service="Utilities.DataAccess.Interfaces.IBaseDAO`1, Utilities.DataAccess"
type="Utilities.DataAccess.BaseDAO`1, Utilities.DataAccess" />
<component
id="NHibernateConnection"
service="Utilities.DataAccess.ConnectionProviders.IConnectionProvider, Finchtils"
type="Utilities.DataAccess.ConnectionProviders.NHibernateConnection" />
<component
id="XMLConnection"
service="Utilities.DataAccess.ConnectionProviders.IConnectionProvider, Finchtils"
type="Utilities.DataAccess.ConnectionProviders.XMLConnection, Utilities" />
</components>
</castle>
</configuration>
Now as some of you may of figured by now, this is a utility library. I intend to use this assembly for each project I create so that I don't have to write the same data access code which remains the same across all solutions. The implications of such of course is that I cannot tell castle exactly what type parameter I will pass to the BaseDAO, in one project it might be a Customer object, another entirely different. I have read on other forums that this is entirely possible as when you request the object from the container you can specify the type then like;
BaseDAO<Customer> baseDao = container.Resolve<BaseDAO<Customer>>();
Although it is against my design efforts, I have tried to use the following notation in the App.config
<component
id="BaseDAO"
service="Utilities.DataAccess.Interfaces.IBaseDAO`1[[Utilities.DataInterface.IEntity]], Finchtills.DataAccess"
type="Utilities.DataAccess.BaseDAO`1[[Utilities.DataInterface.IEntity]], Finchtils.DataAccess" />
However, this has not worked either, in any case I get the following error:
Utilities.Testing.DataAccess.Unit.Testing_BaseDAO (TestFixtureSetUp):
System.Exception : The type name Utilities.DataAccess.BaseDAO`1, Utilities.DataAccess could not be located.
----> System.IO.FileNotFoundException : Could not load file or assembly 'Utilities.DataAccess' or one of its dependencies. The system cannot find the file specified.
Reading this error, I think it could be one of two things:
I am missing something from the config file to do with the generics of the types and services.
I have named something incorrectly I.E an assembly name.
I have treated the assembly name as the project that item is contained within, in other words, at no point have i used <solution name>.<project name>.<item folder>.<item name> but merely started at the project level...I assume that any config option would know what solution it is being called from.
Thank you for any help you may be able to give on this subject.
The assembly name can be found in Visual Studio thus:
In the solution explorer, double-click the properties node
Open the Application tab
Assembly name is near the top right corner
Or, if you're compiling at the command line, you use the /out argument.
Also, you need to specify the assembly for the type arguments (inside the square brackets). So, assuming all your types are in the DataAccess assembly, and that the assembly is called (for brevity's sake) "DataAccess":
<component
id="BaseDAO"
service="Utilities.DataAccess.Interfaces.IBaseDAO`1[[Utilities.DataInterface.IEntity, DataAccess]], DataAccess"
type="Utilities.DataAccess.BaseDAO`1[[Utilities.DataInterface.IEntity, DataAccess]], DataAccess" />
But I agree with other commenters that it's better to do the registrations in code. You don't have to use the verbose type syntax, for one, and you get compiler checking of your types. There are some disadvantages, however: it's harder to tell if you have unused types because the registration call counts as using the type.

Categories