ConfigurationErrorException on null DateTime - c#

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.

Related

How to change the Application scoped value (Settings) without changing it from MyProgam.exe.config?

I have a project(Log) where I used application scope setting(LogLevel) in settings like below which shows the default value:
But now I have used the DLL of this project(Log.dll) in another project(MyProgam through reference) where I want to change the Log Level value. currently it's taking 3 by default as it is saved in Log.dll and I can change the value of LogLevel in second project by updating the value in MyProgam.exe.config.
As per my understanding the application settings come from AppDomain.CurrentDomain.SetupInformation.ConfigurationFile by default which resulted MyProgam.exe.config in my case.
in config it shows like :
<setting name="LogLevel" serializeAs="String">
<value>3</value>
</setting>
So My question is, I want to make the change in LogLevel value (0/1/2) from second project but not through MyProgam.exe.config

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

Dictionary in Settings throws an exception?

I want to save a dictionary in the default UserSettings class of my project.
I've tried the following in the code of the Settings file but it fails:
<Setting Name="MediaKeys" Type="System.Collections.ObjectModel.Dictionary<System.Input.Key, System.IO.FileInfo>" Scope="User">
<Value Profile="(Default)" />
</Setting>
I get this error message when I look at the UI for the Settings:
Could not load file or assembly 'System.IO.FileInfo>' or one of its
dependencies. The parameter is incorrect. (Exception from HRESULT:
0x80070057 (E_INVALIDARG))
Bearing in mind, please, that I will deal with the whole Serializable Dictionary at another point in time, why am I getting this exception? Even non-serializable objects (such as FileInfo, as I have tested) do not throw this exception.
.NET settings do not handle generics very well. This is what I do:
[XmlRoot("dictionary")]
public class MyDictionary : SerializableDictionary<int, string>
{
}

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").

.Net Configuration Editor problem

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.

Categories