Where are the settings saved in a .NET 5 WinForms app? - winforms

In a .NET Framework WinForms project, there was an App.config file in the project, which was an XML file that contained a configSection that would reference a class in System.Configuration, and a section for the userSettings themselves, like so:
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561944e089">
<section name="MyAppName.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561944e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<MyAppName.Properties.Settings>
<setting name="Test" serializeAs="String">
<value>Some Value</value>
</setting>
</MyAppName.Properties.Settings>
</userSettings>
And this created a file in the build folder with the app name plus .exe.config, as in MyAppName.exe.config.
But when I create a new WinForms project using .NET:
There is no App.config in the solution. I can edit the settings using the project properties:
And I can access these values, and update them using the same Properties object and methods:
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
textBox1.Text = Properties.Settings.Default.Test;
}
private void button1_Click(object sender, EventArgs e)
{
Properties.Settings.Default.Test = textBox1.Text;
Properties.Settings.Default.Save();
}
}
}
And everything seems to work, but when I examine the bin folder, there is no file that I can see for where the values are actually stored.
Where is .NET 5 storing the saved application settings if not in a file in the same folder as the application's exe?

User settings are stored in user.config file in the following path:
%userprofile%\appdata\local\<Application name>\<Application uri hash>\<Application version>
Application settings file are not created by default (unexpectedly), however if you create them manually beside the dll/exe file of your application, the configuration system respect to it. The file name should be <Application name>.dll.config. Pay attention to the file extension which is .dll.config.
You may want to take a look at the source code of the following classes:
LocalFileSettingsProvider (The default setting provider)
ClientSettingsStore
ConfigurationManagerInternal
ClientConfigurationPaths
At the time of writing this answer Application Settings for Windows Forms still doesn't have any entry for .NET 5 and redirects to 4.x documentations.

First of all, this is a known (to .NET team) issue: https://github.com/dotnet/project-system/issues/7772.
Secondly the issue and the solution are pretty much described in your question:
(before) ..there was an App.config file in the project,..
(now) There is no App.config in the solution...
Add the missing app.config and everything will work just like it did before.

Related

Why are my application settings retrieving different values to the ones I expect?

I have inherited an application which uses the configuration manager class to store and retrieve settings. In the app.config class there is custom section group "userSettings" which includes a "Server" property.
In the app.config file this value is defined as "a14". In Settings.Designer.vb the default is specified as "a5" yet when I try to access My.Settings.Server it brings back the value "a10", which is a value I previously used in the app.config file.
Not having much experience with the configuration manager, I am at a loss to determine where it is retrieving this value from and what I need to change so that it retrieves the correct server value.
For brevity, I have removed other settings from the code sample.
app.config:
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="WorkstationApp.My.MySettings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
...
<userSettings>
<WorkstationApp.My.MySettings>
<setting name="Server" serializeAs="String">
<value>a14</value>
</setting>
</WorkstationApp.My.MySettings>
</userSettings>
Settings.Designer.vb:
<Global.System.Configuration.UserScopedSettingAttribute(), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Configuration.DefaultSettingValueAttribute("a5")> _
Public Property Server() As String
Get
Return CType(Me("Server"),String)
End Get
Set
Me("Server") = value
End Set
End Property
Application code: (server is being set to "a10", but I want it to have the app.config value of "a14").
Dim Server As String = My.Settings.Server
It looks like I was expecting the wrong thing (well duh). I had these settings set as User settings, which are stored in the /appdata/ folder and had nothing to do with the app.config file at all.
The user config file had been set with the initial values and had never been modified subsequently with a My.Settings.Save. More details in this answer: Where are My.Settings saved in VB 2010 .NET?

WPF handle error/exception from app.config on app startup

I'm trying to capture error in the App.config file on application startup, but I'm not getting.
All global error events (as AppDomain.CurrentDomain.UnhandledException or Application.DispatcherUnhandledException) are not working to catch the incorret format App.Config file, even as the OnStartup method App.xaml, is not being called, the application crashes before.
Sample invalid app.config:
<configuration>
<configSections>
<section name="XXXX" type="TesteAssembly.MainSpace, TesteAssembly" />
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
However, I found that if the App.config file is malformed, to create an instance of the Application class an exception is thrown. Thus, the only solution I found was to remove the App.xaml, create a class with the main method and manually start an instance of Application (App.xaml base class).
example:
[STAThread]
public static void Main(string[] args)
{
try
{
Application p = new Application();
p.StartupUri = new Uri("MainWindow.xaml", UriKind.Relative);
p.Run();
}
catch (Exception)
{
throw;
}
}
There is another solution to this situation?
Try manually loading your config like this to diagnose the problem. Put this code at the start of Main(). It is most likely that the section type name is wrong:
var configMap = new ExeConfigurationFileMap();
configMap.ExeConfigFilename = Assembly.GetExecutingAssembly().Location + ".config";
var config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);

System.DirectoryServices compilation problems

I'm using the code here : ASP.NET How to get List of Groups in Active Directory
Specifically :
using System.DirectoryServices;
DirectoryEntry objADAM = default(DirectoryEntry); //compiler error!
Problem: compiler says that it doesn't know what DirectoryEntry is.
I tried to add it to my web.config:
<assemblies>
<!-- ... -->
<add assembly="System.DirectoryServices, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
</assemblies>
But it didn't seem to help so I tried to add a reference:
Someone suggested setting Copy Local = True but that didn't help either.
I noticed that I don't see a reference for System.DirectoryServices - only System.DirectoryServices.Accountmanagement
Can anyone help me get this code to compile? I'm not sure what to try next.
Take the .net 3.5 filter off in the Add Reference dialog, and then put a reference in your project to:
System.DirectoryServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
You can take the filter off by changing you project setting : http://msdn.microsoft.com/en-us/library/bb398202.aspx
If you want to use the DirectoryEntry from the System.DirectoryServices namespace - you need to add a reference to the System.DirectoryServices assembly - NOT the System.DirectoryServices.AccountManagement assembly!

how to use an external configuration file with WPF?

i would like to set up an external configuration file that I can store in a directory for my WPF app, not necessarily the directory of my exe when I create my program either.
I created an App.Config file and added System.Configuration to my assembly. My App.Config has:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings file="sd.config">
<add key="username" value="joesmith" />
</appSettings>
</configuration>
and my sd.config (external file) which is in the root of my project for now, has
<?xml version="1.0"?>
<appSettings>
<add key="username1" value="janedoe" />
</appSettings>
in my MainWindow cs class I used
string username = ConfigurationManager.AppSettings.Get("username1");
which returns a null string. when i just retrieve the username field from App.Config it works. What did i miss? Thanks so much!
See the documentation on ConfigurationManager:
The AppSettings property:
Gets the AppSettingsSection data for the current application's default
configuration.
You need to do a little extra work to get data that isn't in your application's default configuration file.
Instead of using the file= attribute, add a key to your <appSettings> that defines the location of the secondary config file, like so:
<add key="configFile" value="sd.config"/>
Then, in order to use ConfigurationManager to pull settings from the secondary config file, you need to use its OpenMappedExeConfiguration method, which should look a little something like this:
var map = new ExeConfigurationFileMap();
map.ExeConfigFilename = Path.Combine(
AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
ConfigurationManager.AppSettings["configFile"]
);
//Once you have a Configuration reference to the secondary config file,
//you can access its appSettings collection:
var config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
var userName1 = config.AppSettings["username1"];
That code might not be dead-on for your example, but hopefully it gets you on the right track!

wpf & validation application block > message localization > messageTemplateResource Name&Type

I'm trying to write validation rules for my data objects in a WPF application. I'm writing them in the configuration file, and so far they are working fine.
I'm stumped on how to localize the messages using messageTemplateResourceName and messageTemplateResourceType. What I know is that the strings can be writen in a resource file, given a name and referenced by that name. I get the idea, but i haven't been able to make this work.
<ruleset name="Rule Set">
<properties>
<property name="StringValue">
<validator lowerBound="0" lowerBoundType="Ignore" upperBound="25"
upperBoundType="Inclusive" negated="false" messageTemplate=""
messageTemplateResourceName="msg1" messageTemplateResourceType="Resources"
tag=""
type="Microsoft.Practices.EnterpriseLibrary.Validation.Validators.StringLengthValidator, Microsoft.Practices.EnterpriseLibrary.Validation"
name="String Length Validator" />
</property>
</properties>
</ruleset>
Where is the resource file and what value do I pass to messageTemplateResourceType?
I have tried writing the messages in the shell project's resource file but no sucess trying to retrieve the value. I only get the default built-in message.
I've tried
messageTemplateResourceType="typeof(Resources)"
messageTemplateResourceType="Resources"
messageTemplateResourceType="Resources.resx"
messageTemplateResourceType="typeof(Shell)"
messageTemplateResourceType="Shell"
messageTemplateResourceType="Shell,
Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null"
I've also tried adding a new resource file in the shell project, and adding a resource file to the data object's library. I'm all out of ideas Does anyone have any suggestions? I'm not even married to the idea of resource files, so if there are other ways to localize these messages I'd love to know!
thanks
You need to create your own resource file and then point the messageTemplateResourceType attribute to your fully qualified resource type. As long as the resource file can be loaded at runtime you should be fine.
<ruleset name="Rule Set">
...
messageTemplateResourceName="msg1"
messageTemplateResourceType="My.Fully.Qualified.ResourceType, My.AssemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
...
</ruleset>
An alternate way to do it would be use the messageTemplate as a key and write custom code to look up the actual localized string based on the messageTemplate key (either from a resource file or from a database or wherever else you are storing it).

Resources