I have application 1 and application 2. App2 needs to verify that App1 is installed, and if it is it needs to access a property from the App1 Settings.
What would be the best way to go about this?
UPDATE
First, my apologies for never accepting an answer to this, I know it's over a year old now, but I got sidetracked immediately after asking this and then the project was changed, blah blah blah. Mea culpa...
I'm back on it now and I still need to solve this problem, but now the applications are deployed via ClickOnce, so I don't actually know where they are located. Any suggestions would be appreciated. I promise I'll select an answer this time.
The docs for ConfigurationManager.OpenExeConfiguration have an example of reading the .config file of another exe and accessing the AppSettings. Here it is:
// Get the application path.
string exePath = System.IO.Path.Combine(
Environment.CurrentDirectory, "ConfigurationManager.exe");
// Get the configuration file.
System.Configuration.Configuration config =
ConfigurationManager.OpenExeConfiguration(exePath);
// Get the AppSetins section.
AppSettingsSection appSettingSection = config.AppSettings;
As far as checking that App1 is installed, you could write a value in the Registry during installation and check it in App2 (and remove the value during uninstall).
This is a pain, I can tell you that much. I've found that the best way to do this is that you serialize the Settingsclass and use XML(code below). But try this page first:
http://cf-bill.blogspot.com/2007/10/visual-studio-sharing-one-file-between.html
public class Settings
{
public static string ConfigFile{get{return "Config.XML";}}
public string Property1 { get; set; }
/// <summary>
/// Saves the settings to the Xml-file
/// </summary>
public void Save()
{
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
using (TextWriter reader = new StreamWriter(ConfigFile))
{
serializer.Serialize(reader, this);
}
}
/// <summary>
/// Reloads the settings from the Xml-file
/// </summary>
/// <returns>Settings loaded from file</returns>
public static Settings Load()
{
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
using (TextReader reader = new StreamReader(ConfigFile))
{
return serializer.Deserialize(reader) as Settings;
}
}
}
Related
I have a pair of apps. One is a game for young kids. The other is a tool for use by the parents. I separate the apps in this way to keep the UI as simple as possible for the kids.
One part of the parent app is to control specific settings of the kids' app. I've just been using Settings.settings for most of my settings up to now, but can't see a simple way for the parent app to access and change the settings in the kids' app (apart from a rather kludgy back-door using XML).
Is there a way, or alternatively, is there another place I should consider keeping my shared settings?
I like the ease of two-way binding for managing settings via a dialog, but could survive without that if necessary.
FWIW: Both apps do use a common DLL where a lot of common code resides. Maybe there's a way of leveraging that?
You can save the settings to a file into a common folder like the below (eg C:\ProgramData\yourfolder)
String DataPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\yourfolder";
and access the settings file from both applications. No need of a database and easy of use.
The settings file can be a simple json or whatever you feel comfortable.
In the end, I went with having a class that contains the shared settings. Here's the main part of it:
public class AppConfig
{
public int SaveSize = 1000;
//... other shared settings here
static private bool ready = false;
static private AppConfig instance;
static public AppConfig Instance
{
get
{
if (!ready)
{
ReadFromFile();
}
return instance;
}
}
static private readonly string filename = Common.AppDataFileName("config.xml");
static private void ReadFromFile()
{
ready = true;
if (!File.Exists(filename))
{
instance = new AppConfig();
return;
}
XmlSerializer serializer = new XmlSerializer(typeof(AppConfig));
using (FileStream fs = new FileStream(filename, FileMode.Open))
{
instance = (AppConfig)serializer.Deserialize(fs);
}
}
static public void Save()
{
XmlSerializer serializer = new XmlSerializer(typeof(AppConfig));
using (TextWriter writer = new StreamWriter(filename))
{
serializer.Serialize(writer, Instance);
}
}
}
Because you have to have an instance for serialization, I instantiate that on-demand and then refer to it as needed. E.g.:
int size = AppConfig.Instance.SaveSize;
Don't know if this is the best way, but it works for my needs for now. If it is a bad way to do this, don't be shy to comment below. I'm here to learn!
I am trying to debug code from https://nunrar.codeplex.com/. In branch DOCUMENTATION -> Basic Usage there is the following code:
RarArchive archive = RarArchive.Open(source);
foreach (RarArchiveEntry entry in archive.Entries)
{
string path = Path.Combine(destination, Path.GetFileName(entry.FilePath));
entry.ExtractToFile(path);
}
Well.. I 've downloaded source code, find RarArchiveEntry class and started to looking for method ExtractToFile(), but there isn't any method there neither in class, nor in project!
Please help me to find this method or method which i can call to look through how this programm can unpack rar files step-by-step?
It looks like the documentation is obsolete and the name of the method was changed, there is an extension method found in RarArchiveEntry.Exensions.cs called WriteToFile.
/// <summary>
/// Extract to specific file
/// </summary>
public static void WriteToFile(this RarArchiveEntry entry, string destinationFileName, ExtractOptions options = ExtractOptions.Overwrite)
{
entry.WriteToFile(destinationFileName, new NullRarExtractionListener(), options);
}
I have a C# application with a settings field that is a collection of custom objects.
When I start the application I create some class instances that take instances from the settings entry collection and keep a reference to them internally and modify them. While debugging I saw that changes done through these external references are not reflected when I callSettings.Default.Save() but changes done by directly accessing the properties likeSettings.Default.<property> work fine.
I looked up the code responsible for Save() and saw that the implementation actually checks a SettingsPropertyValue.IsDirty field to decide whether to or not to serialize it. Of course when I access the external references to the objects in the settings field that value is not set.
Is there any lightweight solution to this?
I don't think I'm the first person to encounter this. One way I can think of is implementing the IsDirty property in the collections I serialize and add INotifyPropertyChanged interface event PropertyChanged for all the contained instances so that the container is being notified of changes and can reflect them to the actual settings property. But that means wrapping each of the settings classes around with this logic. So what I am asking for is if there is a lightweight solution to this found by anyone else who has encountered this issue.
Example
Consider this class:
namespace SettingsTest
{
[DataContract(Name="SettingsObject")]
public class SettingsObject
{
[DataMember]
public string Property { get; set; }
}
}
And the following program:
namespace SettingsTest
{
class Program
{
static void Main(string[] args)
{
var settingsObjects = new List<SettingsObject>();
var settingsObject = new SettingsObject{Property = "foo"};
settingsObjects.Add(settingsObject);
Settings.Default.SettingsObjects = settingsObjects;
Settings.Default.Save();
settingsObject.Property = "bar";
Settings.Default.Save();
}
}
}
After the second Save() call the final output in user.config file is:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<userSettings>
<SettingsTest.Settings>
<setting name="SettingsObjects" serializeAs="Xml">
<value>
<ArrayOfSettingsObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SettingsObject>
<Property>foo</Property>
</SettingsObject>
</ArrayOfSettingsObject>
</value>
</setting>
</SettingsTest.Settings>
</userSettings>
</configuration>
As you can see the modification to the property via the external reference to the SettingsObject instance was not persisted.
You seem to be covering a bunch of issues with this question. As you correctly said "changes done by directly accessing the properties likeSettings.Default. work fine." Modifying in memory references will not cause the settings to be updated automatically as you wanted. INotifyProperty changed is one solution.
If you want a quick and dirty method of serializing these objects into your settings file you can use the following code.
Objects involved:
/// <summary>Generic class to support serializing lists/collections to a settings file.</summary>
[Serializable()]
public class SettingsList<T> : System.Collections.ObjectModel.Collection<T>
{
public string ToBase64()
{
// If you don't want a crash& burn at runtime should probaby add
// this guard clause in: 'if (typeof(T).IsDefined(typeof(SerializableAttribute), false))'
using (var stream = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
stream.Position = 0;
byte[] buffer = new byte[(int)stream.Length];
stream.Read(buffer, 0, buffer.Length);
return Convert.ToBase64String(buffer);
}
}
public static SettingsList<T> FromBase64(string settingsList)
{
using (var stream = new MemoryStream(Convert.FromBase64String(settingsList)))
{
var deserialized = new BinaryFormatter().Deserialize(stream);
return (SettingsList<T>)deserialized;
}
}
}
[Serializable()]
public class SettingsObject
{
public string Property { get; set; }
public SettingsObject()
{
}
}
The main method demonstrates the issue you are facing, with a solution.
class Program
{
static void Main(string[] args)
{
// Make sure we don't overwrite the previous run's settings.
if (String.IsNullOrEmpty(Settings.Default.SettingsObjects))
{
// Create the initial settings.
var list = new SettingsList<SettingsObject> {
new SettingsObject { Property = "alpha" },
new SettingsObject { Property = "beta" }
};
Console.WriteLine("settingsObject.Property[0] is {0}", list[0].Property);
//Save initial values to Settings
Settings.Default.SettingsObjects = list.ToBase64();
Settings.Default.Save();
// Change a property
list[0].Property = "theta";
// This is where you went wrong, settings will not be persisted at this point
// because you have only modified the in memory list.
// You need to set the property on settings again to persist the value.
Settings.Default.SettingsObjects = list.ToBase64();
Settings.Default.Save();
}
// pull that property back out & make sure it saved.
var deserialized = SettingsList<SettingsObject>.FromBase64(Settings.Default.SettingsObjects);
Console.WriteLine("settingsObject.Property[0] is {0}", deserialized[0].Property);
Console.WriteLine("Finished! Press any key to continue.");
Console.ReadKey();
}
}
So all I'm doing is storing your whole list of objects as a base64 encoded string. Then we deserialize on the next run.
From what I understand of the question you want to only hold in memory references without hitting the settings object. You could simply run some code at the end of main to persist this list and any other setting you need to. Any changes will still be in memory as long as you hold a reference the object & will remain around until you terminate the application.
If you need the settings to be saved while the application is running just create a Save() method of your own & call it from the end of Main() as well when the user performs an action that requires saving the settings. e.g.
public static void SaveSettings(SettingsList list)
{
Settings.Default.SettingsObjects = list.ToBase64();
Settings.Default.Save();
}
Edit: One caveat as mentioned in the comments below.
From my benchmarks this method is very slow, meaning it's not a good idea to persist large object lists in settings this way. Once you have more than a handful of properties you might want to look at an embedded database like SQLite. A CSV, INI or XML file could also be an option here for large numbers of trivial settings. One benefit of simpler storage formats is easy modification by non-developers eg csv in excel. Of course this may not be what you want ;)
I am trying to get value of service in my application from app.config. I have to send it to the application which shows the URL. A web service which I am consuming in this aplication also using it so can not move it to appSettings.
I want to get this value 'http://192.168.4.22:82/Service.asmx' through c# code.
<applicationSettings>
<SDHSServer.Properties.Settings>
<setting name="DOServer_WebReference1_Service" serializeAs="String">
<value>http://192.168.4.22:82/Service.asmx</value>
</setting>
</SDHSServer.Properties.Settings>
</applicationSettings>
Not sure i get the question,
string s = SDHSServer.Properties.Settings.DOServer_WebReference1_Service;
will get you it
If I understand you correctly you have two Visual Studio C# projects. The first (project A) has a setting you want to access in the second (project B). To do that you have to perform the following steps:
Add a reference from project B to project A
Change the access modifier of the settings i project A to public (default is internal)
Now you can access the setting in project B, in your case using the fully qualified name SDHSServer.Properties.Settings.Default.DOServer_WebReference1_Service
Note that in the settings editor you can set a value for the setting. This is the default value for the setting and this value is also stored in the App.config file for the project. However, you can override this value by providing another value in the App.config file for the application executing.
In this example, the App.config file for project A will contain the value for the setting which is http://192.168.4.22:82/Service.asmx. However, you can override this in the App.config file for project B to get another value. That is probably not what you want to do but you should be aware of this.
I use this code in a ASP.Net 4.0 site to pull section data out of the 'applicationsetting' section:
public sealed class SiteSupport {
/// <summary>
/// Retrieve specific section value from the web.config
/// </summary>
/// <param name="configSection">Main Web.config section</param>
/// <param name="subSection">Child Section{One layer down}</param>
/// <param name="innersection">Keyed on Section Name</param>
/// <param name="propertyName">Element property name</param>
/// <returns></returns>
/// <example>string setting = NoordWorld.Common.Utilities.SiteSupport.RetrieveApplicationSetting("applicationSettings", "NoordWorld.ServiceSite.Properties.Settings", "ServiceWS_SrvWebReference_Service", "value")</example>
public static string RetrieveApplicationSetting(string configSection, string subSection, string innersection, string propertyName) {
string result = string.Empty;
HttpWorkerRequest fakeWorkerRequest = null;
try {
using (TextWriter textWriter = new StringWriter()) {
fakeWorkerRequest = new SimpleWorkerRequest("default.aspx", "", textWriter);
var fakeHTTPContext = new HttpContext(fakeWorkerRequest);
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap() { ExeConfigFilename = fakeHTTPContext.Server.MapPath(#"~/Web.config") }, ConfigurationUserLevel.None);
ConfigurationSectionGroup group = config.SectionGroups[configSection];
if (group != null) {
ClientSettingsSection clientSection = group.Sections[subSection] as ClientSettingsSection;
if (clientSection != null) {
SettingElement settingElement = clientSection.Settings.Get(innersection);
if (settingElement != null) {
result = (((SettingValueElement)(settingElement.ElementInformation.Properties[propertyName].Value)).ValueXml).InnerText;
}
}
}
}
} catch (Exception ex) {
throw ex;
} finally {
fakeWorkerRequest.CloseConnection();
}
return result;
}
}
https://www.ServiceWS.com/webservices/Golf
Depends something like this.
var s = SDHSServer.Properties.Settings.Default.DOServer_WebReference1_Service;
or
var s = SDHSServer.Properties.Settings.DOServer_WebReference1_Service;
In my C# program that is made with Visual Studio 2010 and uses WinForms, I would like the program to save state of some checkboxes and textboxes so the next time program will be loaded they are checked or unchecked as theire last run's state. Also same with strings inside textboxes and etc...
What will be the proper way to achieve this? Is there a built in stuff in .NET? Any tips and code snippets would be appriciated!
Thanks
You'd probably want to look at reading the relevant values from your UI during the FormClosing event, and then saving them into User Settings.
Have a look at: http://codehill.com/2009/01/saving-user-and-application-settings-in-winforms/
I would bind the value to user settings, and saving the configuration OnClose event.
One way to do this is using an XML configuration file and serializing it:
ConfigManager.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
namespace MyApplication
{ [ Serializable() ]
public class ConfigManager
{
private int removeDays = 7;
public ConfigManager() { }
public int RemoveDays
{
get
{
return removeDays;
}
set
{
removeDays = value;
}
}
}
somewhere in your application
private ConfigManager cm;
private XmlSerializer ser;
...
Then you have to load the configuration:
private void LoadConfig()
{
try
{
cm = new ConfigManager();
ser = new XmlSerializer(typeof(ConfigManager));
filepath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + cm.filepath;
if (File.Exists(filepath))
{
FileStream fs = new FileStream(filepath, FileMode.Open);
cm = (ConfigManager)ser.Deserialize(fs);
// do something
}
} catch (Exception ex) { }
}
To save it:
XmlSerializer ser;
ConfigManager cm;
...
private void saveConfig()
{
try {
cm.RemoveDays = 6;
TextWriter tw = new StreamWriter(filepath, false);
ser.Serialize(tw, cm);
tw.Close();
} catch (Exception ex)
}
You asked very broad question. there are two ways to look at it.
1) If you have a need to persist application level configuration, your best bet is to use Application Settings. One can serialize program settings the user has done using your app, and restore them after the program has restarted. This works with WinForms and WPF:
2) If you need user level persistence, you need user settings.
Also, you can create custom class that implements that stores all of the configuration properties that you need.
Implement ISerializable and mark it [Serializable]. You could just mark it [Serializable], but if you add new properties in the future, you'll run into deserialization problems.
Add a Version property.
Add two static methods: Load and Save. These methods use IsolatedStorage to deserialize/serialize your configuration class to disk. You can use any kind of serialization you want - I use binary. Why not XML? Because binary is faster and users never need to get into these files. I used to do this for .net 2.0.