I have multiple .NET assemblies that all need to share common user settings, such as preferences, user names, etc. One is a WPF application, another is a console application, and the third is an Office Add-in. All of these settings are user-scope.
Only the WPF application needs to be able to change settings. The rest just read them.
Ideally, I'd like to use the .NET configuration framework. I'm not sure how to do this though. If I add Settings to the WPF application, how can the other applications find the user.config file?
Is it just easier to create a class library and use IsolatedFileStorage and serialize my settings?
Any advice would be greatly appreciated.
You can implement your custom settings class, inheriting ApplicationSettingsBase. As a good start, you can add the default User Settings file to a sample project (Right click on the project -> Properties -> Settings -> This project does not contain a default settings file. Click here to create one.). Add a user-scoped setting and investigate the structure of the designer-generated Settings.Designer.cs file:
namespace ConsoleApplication1.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("John Doe")]
public string Name {
get {
return ((string)(this["Name"]));
}
set {
this["Name"] = value;
}
}
}
}
In your custom implementation, you will not be limited to the designer-generated access modifiers, so you can implement the Settings class as internal with internal setters, visible only to the needed assemblies, or whatever fits your needs.
Of course, you can always implement your custom serialize/deserialize mechanism, but you will lose the funcionality provided by ApplicationSettingsBase's Updgrade, Reload, and Reset methods. If you don't need any of these, this could be the cleaner approach.
I would recommend you to create service to provide and update user info and or preferences. It will be better architecture, cleaner solution and it will be easier to maintain and extend.
Related
I would like to know if there is some kind of built-in compiled "App.Config" file?
The goal is to be able to have one of our library which can have some of its default values overriden when being used in some client application.
Thoses DLL are loaded dynamically, so I cannot just give a parameter in the constructor.
I don't want to use the App.config file because the user can edit those values(otherwise it would have been just fine).
There are several different ways to solve this.
If you like the idea of config-files, but do not want to have it accessible by end users in the compiled application, perhaps you can create your own settings-file in a format that suits your needs, and include it as an embedded resource?
An upside of this would be that you can access it as a regular XML or config file or whatever in Visual Studio, while it will be hidden from the end user. Personally I think I would prefer this to using special code / classes to store config-data.
To include a file as an embedded resource, include it into one of your Visual Studio projects, right click the included file and select Properties. Now under Build Action, select Embedded Resource. When you build your project now, the file will be included internally in the produced .dll-file.
I'm sure you'll be able to find lot's of info about how to access an embedded resource from code. As an example, there are some useful examples in this SO question. Note especially this answer, which also mentions an alternative way to include a resource.
Expanding on my comment... you could just make an interface for a settings class with hardcoded values, and then make different implementations of that interface. To actually change which one to use, all you'd need to do is comment/uncomment the line that instantiates an object into your settings variable before you build the dll:
public class MainDllProject
{
ISettings m_Settings;
public MainDllProject()
{
// Change this before compiling
this.m_Settings = new DebugSettings();
//this.m_Settings = new DeploySettings();
// use settings from the settings class
String setting1 = this.m_Settings.Setting1
Int32 setting2 = this.m_Settings.Setting2
//...
}
}
public interface ISettings
{
String Setting1 { get; }
Int32 Setting2 { get; }
}
public class DebugSettings: ISettings
{
public String Setting1
{ get { return "data_debug";} }
public Int32 Setting2
{ get { return 2;} }
}
public class DeploySettings: ISettings
{
public String Setting1
{ get { return "data_deploy";} }
public Int32 Setting2
{ get { return 1;} }
}
On finding "a built-in way of solving this", as you said, maybe this will be useful for you...
You can actually use the Visual Studio build configuration manager to build with different settings. Using the #If directives, you can automatically make it select which lines of code to use based on the configuration. A simple example based on the default debug configuration, which adds the "DEBUG=True" variable automatically:
public MainDllProject()
{
#If DEBUG Then
this.m_Settings = new DebugSettings();
#ElseIf
this.m_Settings = new DeploySettings();
#End if
}
You can actually make your own custom-named variables to check on just like that DEBUG one: after making a configuration, open the Project properties window, go to the Compile tab, select that specific configuration in the dropdown, and then at the bottom select "Advanced Compile Options". In there is a line "Custom constants" in which you can add such variables. For simple if-statements, you can just make a boolean like "CLIENTDEPLOY=True", and then you can use #If CLIENTDEPLOY Then in your code.
We are implementing a plug and play module for our application where user can load and unload the desired class library at runtime. So I have decided to use MEF and shadow copying of class libraries.
The thing here is each class library may have different configuration properties which needs to set by user. My main application has no knowledge about the configurations present in the class library.
Now the problem is when I try to transfer the application configuration file loaded with class library from one application domain to another.
Without MEF, I have just returned Settings.Default from the class library and I have used it in our main application to edit the settings. With MEF and shadow copying, It doesn't seems to be working because
The object type needs to known to both sides.
I cannot implement MarshalByRefObject on the settings file since
the settings file is already extending ApplicationSettingsBase which
is an abstract class and c# doesn't supports multiple inheritance.
Currently I am creating a class which holds all the properties as string and creating a GUI in my main application based on this class content.
public class ExtensionModuleConfiguration : MarshalByRefObject
{
public string Name { get; set; }
public string Value { get; set; }
public List<string> Options { get; set; }
public UIElements ToolUIElement { get; set; }
}
public enum UIElements
{
ComboBox,
TextBox
}
I must say this is not the best solution.
Can someone suggest a better way to set the configurations of a class library in MEF?
There two ways how you can do it. You must inform .NET which app.config should be loaded in the appdomain of your MEF plugin class.
Therefore you can either point particular app.config for your plugin DLL like this:
ConfigurationManager.OpenExeConfiguration("Plugin.dll");
var name = AppSettings.Settings["Name"].Value;
Or you can load the app.config for your main application DLL and put all the appsettings in that file. In this case you should do:
var config = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location);
var name = config.AppSettings.Settings["Name"].Value;
Both solutions should be called from within of you Plugin implementation for example in constructor. Or by first call to some lazy loaded configuration property.
I have a windows application that writes user settings using the method described here:
http://msdn.microsoft.com/en-us/library/bb397755(v=vs.110).aspx
These settings are saved to a file in the users directory e.g:
c:\users\{you name}\Local\{Company}\{product}\user.config
I need to access these settings in a companion console application. Is this possible, at the moment the settings return null when I try to access them from the console application.
The code itself will look something like this:
To save the settings in App1:
namespace Application1{
public class DemoSave{
public void DoWork(){
Application1.Properties.Settings.Default.CustomSettings.Title ="someValue";
Application1.Properties.Settings.Default.Save();
}
}
}
To read the settings in another app:
namespace Application2{
public class Demo{
public void DoWork(){
var title = Application1.Properties.Settings.Default.CustomSettings.Title;
}
}
}
In Application2 the Application1.Properties.Settings.Default.CustomSettings property is null.
Last time I did something similar, I had two projects in a solution (a windows service and a wpf application), and I had to reference the WPF app in the Win Service project to access it's settings (I assume you're talking about Namespace.Properties.Settings). It seems to have worked fine for me. In this case i had to set the access modifier on the settings to public though. I'm not sure if this is the best way, but it worked for me for something very small and insignificant.
Are you even sure your pointing at the right place when you modifies/read the settings files.
Because that might be why it doesn't work.
i have a class library, with domain objects (linq based objects, in .net
4.0).
i want to have this library use connection strings for its own app.config.
there are some problems:
following the model used by Settings : ApplicationSettingsBase, i created a
wrapper that should read the settings from app.config.
however, unlike the model, i provide default values.
the problem is that the properties which should load the data from app.config
internal sealed class ApplicationSettings : ApplicationSettingsBase
{
// other properties
[SpecialSetting( SpecialSetting.ConnectionString )]
[global::System.Configuration.DefaultSettingValueAttribute("Server=.;Database=RFPLUSSTD;User Id=SYSADM;Password=SYSADM;")]
public string MainConnectionString
{
get { return (string)this["MainConnectionString"]; }
}
// other properties
}
in app.config:
<connectionStrings>
<add name="MainConnectionString"
connectionString="..."
providerName="System.Data.SqlClient" />
</connectionStrings>
now, this doesn't work...
i tried to set the name of the conn string to the fully qualified name like
namespace.class.property, but to avail.
i don't want to use the default Settings class, used by the dbml because
it compiles the settings :D and i can't change them without recompiling...
i'm already using a different model of app settings class in a project in
1.1, but i thought 3.5 has grown enough and have its own objects, that
work..
So, why is not working and how can i make it work?
Thank you
You need to make sure that you have permissions in the file system to make the change. I hope you have considered that. If you are sure that you changed the config file and if it only brings the default settings, it might be loading the config file from output bin folder not in the project root. If you are sure that the modification fails, please post the error message.
Updated:
Hi Jack, I think the main issue with your code is that it is creating new instance of the ApplicationSettings class every time and if the setting is in user scope, you will be having null value and then it results to default value every time.
You could easily do it with the built in Settings class. By default the Settings can only be accessed within the Assembly, internal sealed partial class Settings (in Settings.Designer.cs). If you change this to public sealed you will be able to access the Settings from any assembly and the next thing is you have to keep the setting to Application Scope not User scope. Once you have done these two, you can retrieve and save without any problem.
My current solution has 3 project with 2 app.config (one for common settings and another for service settings). As of now I'm simply creating static classes to act as a mediator to access values. I do this so I don't have to write ConfigurationManager.AppSettings["SomeKey"] everywhere. This works fine until you want to access an app.config file from a different project.
Here is what I'm currently doing (all properties omitted for brevity).
public class ServiceConfiguration
{
public static readonly string SyncEvery = ConfigurationManager.AppSettings["SyncEveryMinutes"];
}
How can I access an app.config file located in another project? I thought perhaps setting VS to copy the file to the output directory would do the trick however my configuration object is still null.
I can't imaging many good reasons to read another app's configuration in the first place, it just opens a can of worms that isn't worth dealing with.
Expose a class that exposes the project's configured values as properties, and access them from a consuming class.
public class FirstProjectClass
{
public static int SyncEveryMinutes
{
get { return (int)ConfigurationManager.AppSetting["SyncEveryMinutes"] };
}
}
public class SecondProjectClass
{
public void ShowConfigedValue()
{
Console.Writeline("Syncing every {0} minutes", FirstProjectClass.SyncEveryMinutes);
}
}
if you've got complex configuration requirements you can also look into custom configuration sections
ConfigurationManager.OpenExeConfiguration can be helpfull:
http://msdn.microsoft.com/en-us/library/system.configuration.configurationmanager.openexeconfiguration.aspx
Also: what Jason said - it is usually a bad idea.