my project has been an extremely fun journey so far but I am looking to save the configuration of the Server settings that it will connect (using MySQL Net/Connector).
When the application has loaded up, by default it connects to a server named 'sqlserver05' but I want the user/admin to be able to configure the server settings in a menustrip. So I navigate to the menustrip and you can click 'Configure' where another form pops up asking for server details.
I can do this just by a global string but I have to change the settings everytime the application runs. Can I not create an XML file to read the configuration settings that I just changed?
Sorry if I am not being clear. Many thanks,
Brandon
Yes, you can. An easy way to do this is to use application settings. This is an out-of-the-box implementation of (user and program) settings that is serialized to XML.
Please take a look at the ancient, but still applicable Using Settings in C#.
Effectively what you have to do:
Add a settings file to your project. Go the the Solution Explorer, right click on your project and select Properties. Then select Settings. Follow the steps there.
Create a setting. (In the following code it has the name PropertyName)
Get and set that setting in code.
string value = Properties.Settings.PropertyName; // get
Properties.Settings.Default.PropertyName = value; // set
Save the settings when you have changed anything:
Properties.Settings.Default.Save()
I think in your case it's better to use the Settings class that came with C#, take a look at these links.
1 , 2
First of all, create a simple POCO object to handle the value you wish to set, then read / write this object through a serializer.
You could use a Javascript serializer to generate a JSON file (which is more "trendy" than XML, but if you prefer XML, the mechanism remains the same) :
class DatabaseSettings
{
// Settings file path
private const string DEFAULT_FILENAME = "settings.json";
// Server name or IP
public string Server { get; set; } = "127.0.0.1";
// Port
public int Port { get; set; } = 3306;
// Login
public string Login { get; set; } = "root";
// Password
public string Password { get; set; }
public void Save(string fileName = DEFAULT_FILENAME)
{
File.WriteAllText(
fileName,
(new JavaScriptSerializer()).Serialize(this));
}
public static DatabaseSettings Load(string fileName = DEFAULT_FILENAME)
{
var settings = new DatabaseSettings();
if (File.Exists(fileName))
settings = (new JavaScriptSerializer()).Deserialize<DatabaseSettings>(File.ReadAllText(fileName));
return settings;
}
}
Usage is then the following :
// Read
var settings = DatabaseSettings.Load(/* your path */);
// update
settings.Server = "10.10.10.2";
// save
settings.Save(/* your path */);
Related
C# Windows Forms.
I have successfully used Application Settings to save and load user settings for the values of controls on my form.
I have a checkbox and code where I can set whether this happens automatically (at application start and close), or not.
I also have a menu so I can load them and save them during runtime.
This is all using the default user.config.
Example.
In Application settings I have (for one of the items, which is a radio button called RbBitRate6Mbps):
Name: BitRate6Mbps
Type: String
Scope: User
Value: False
To save the settings I have a menu item, Save Defaults. This runs:
if (RbBitRate6Mbps.Checked == true)
{
Settings.Default["BitRate6Mbps"] = "True";
}
else
{
Settings.Default["BitRate6Mbps"] = "False";
}
Settings.Default.Save();
To load the settings back in I have a menu item, Load Defaults. This runs:
if (Settings.Default["BitRate6Mbps"].ToString() == "True")
{
RbBitRate6Mbps.Checked = true;
}
else
{
RbBitRate6Mbps.Checked = false;
}
There are about 10 other controls I save and load (text boxes, check boxes and radio buttons), in the rest of the above code.
This is all working with no issues.
Now I would like to have several sets of these settings, each will contain some identical values and some different ones.
Each will have a different file name and be saved into a custom location (which will be the app folder, by default).
I do not mind what format the file is (xml, ini, etc), but if it is the same as the default, this would be good.
I have created new menu items, Save Custom Settings and Load Custom Settings.
I have added a SaveFileDialog and a LoadFileDialog to hopefully be used for the above.
But if these are not necessay, that is good too.
This is where I have become stuck.
I have been searching for days for a clear example of how to do this.
I have been unable to find much. What I have found, I have been unable to understand the documentation.
I am thinking loading the settings back in will be the easier part?
But I also think, for saving the file, using:
Settings.Default.Save();
Will not accomplish my aims as it will just write to the default user.config file ?
Is what I want to do possible?
If so does anyone have any instructions and example code?
Update. I have installed a new Settings Provider and it is working well. It saves the XML to the app folder. I have also set up INI files to save the settings. Using both a custom path and custom file name. It allows for multiple INI files to be created. This also works extremely well.
Edit: Updated code (and instructions) so it is no longer necessary to create any custom folder manually. If it does not exist, it will be created.
The XML Settings Provider developers project is located here:
Settings Providers on Github
The INI file developers project (and demo) is located here:
C# WinForms Ini File demo on Github
Below are the instructions for setting up the new Settings Provider with an XML file and following that are the instructions for saving the settings to INI files (both types can be used in the same project at the same time, as I am doing here):
Using a new Settings Provider to save settings in an XML file:
1.
Setup the Application Settings (in Solution Explorer, right-click on the App. Then Select: Properties. Then open: Settings).
Name: txtFullName
Type: String
Scope: User
Value: John Doe
Name: txtSchool
Type: String
Scope: User
Value: Oxford
Name: txtClass
Type: String
Scope: User
Value: 4B
Name: chkActiveStudent
Type: bool
Scope: User
Value: True
2.
Install, from NuGet the new Settings Provider (in Solution Explorer, right-click on: References. Then Select: Manage NuGet Packages. Then search for: PortableSettingsProvider. Install it).
3.
In Program.cs modify static void Main(). Add to it the lines below.
//PortableSettingsProvider.SettingsFileName = "portable.config";
//PortableSettingsProvider.SettingsDirectory = "c:\\\testconfig\\\school";
//System.IO.Directory.CreateDirectory(PortableSettingsProvider.SettingsDirectory);
PortableSettingsProvider.ApplyProvider(Properties.Settings.Default);
If accepting the default settings (the config file, portable.config, will be created in the applications folder), a properly edited static void Main() entry would look like the below.
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//PortableSettingsProvider.SettingsFileName = "portable.config";
//PortableSettingsProvider.SettingsDirectory = "c:\\testconfig\\school";
//System.IO.Directory.CreateDirectory(PortableSettingsProvider.SettingsDirectory);
PortableSettingsProvider.ApplyProvider(Properties.Settings.Default);
Application.Run(new MyTestApp());
}
3a.
To choose a different filename and location, remove the comments (//) and change to your preference for filename and location (double slashes are needed between the folder names). In this example I use settings.config as the filename and c:\testconfig\school as the path). In this case a properly edited static void Main() entry would look like the below.
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
PortableSettingsProvider.SettingsFileName = "settings.config";
PortableSettingsProvider.SettingsDirectory = "c:\\testconfig\\school";
System.IO.Directory.CreateDirectory(PortableSettingsProvider.SettingsDirectory);
PortableSettingsProvider.ApplyProvider(Properties.Settings.Default);
Application.Run(new MyTestApp());
}
3b.
If you would like the settings directory to be created in a subfolder of the applications working directory, then change the code to include the subfolder name (in this example I use settings.config as the filename and Settings as the subfolder). In this case a properly edited static void Main() entry would look like the below.
static void Main()
{
Application.EnableVisualStyles();
PortableSettingsProvider.SettingsFileName = "settings.config";
var strSettingsDirectory = Directory.GetCurrentDirectory() + "\\Settings";
System.IO.Directory.CreateDirectory(strSettingsDirectory);
PortableSettingsProvider.SettingsDirectory = strSettingsDirectory;
PortableSettingsProvider.ApplyProvider(Properties.Settings.Default);
Application.Run(new MyTestApp());
}
4.
Still in Program.cs, add the following line to the bottom of the existing using section.
using Bluegrams.Application;
5.
On the form create some controls (these will correspond to the Application Settings made in step 1).
TextBox. Name: txtFullName
TextBox. Name: txtSchool
Textbox. Name: txtClass
Checkbox. Name: chkActiveStudent
Button. Name: btnLoadSettings Text: Load Config
Button. Name: btnSaveSettings Text: Save Config
6.
Enter the code for the Load Config buttons click events (btnLoadSettings).
private void btnLoadSettings_Click(object sender, EventArgs e)
{
txtName.Text = Properties.Settings.Default.txtName.ToString();
txtSchool.Text = Properties.Settings.Default.txtSchool.ToString();
txtClass.Text = Properties.Settings.Default.txtClass.ToString();
if (Properties.Settings.Default.chkActiveStudent == true)
{
chkActiveStudent.Checked = true;
}
else
{
chkActiveStudent.Checked = false;
}
}
7.
Enter the code for the Save Config buttons click events (btnSaveSettings).
private void btnSaveSettings_Click(object sender, EventArgs e)
{
Properties.Settings.Default.txtName = txtName.Text;
Properties.Settings.Default.txtSchool = txtSchool.Text;
Properties.Settings.Default.txtClass = txtClass.Text;
if (chkActiveStudent.Checked == true)
{
Properties.Settings.Default.chkActiveStudent = true;
}
else
{
Properties.Settings.Default.chkActiveStudent = false;
}
Properties.Settings.Default.Save();
}
8.
That’s it.
Run the app.
Load the settings using the first button).
Make some changes to the text on the controls.
Save them using the second button.
If you have not created a custom filename and/or path then in your app folder there should be a new file: portable.config.
Mine is located at: C:\Users\flakie\source\repos\TestApp\TestApp\bin\Debug
You can open the file in an txt/xml editor to verify the values were set.
If you run the app again, and load settings, you should see the new values.
The Code for Saving Settings to Multiple INI Files
The following instructions are easier to implement.
They do not require you to set-up the Application Settings as they are not used.
The settings will be saved in 1 or more INI files.
The path can be changed on-the-fly (though a default is set), as can the file name for the INI file.
Again it will be using the applications own folder as the default destination (for the INI files).
You will need to modify the Form.cs file only.
The demo (from the link above) is easy to understand and was enough to provide me with the knowledge to create this example (and I am a C# novice).
9.
Install, from NuGet, the INI files package (in Solution Explorer, right-click on: References. Then Select: Manage NuGet Packages. Then search for: PeanutButter.INI. Install it).
10.
In your Form.cs file (Form1.cs if you have not changed the name), add the following line to the bottom of the existing using section.
using PeanutButter.INIFile;
11.
In your Form.cs file, directly under the line, public partial class Form1 : Form, add the following single line of code.
private IINIFile _loadedConfig;
It should look like the below.
public partial class Form1 : Form {
private IINIFile _loadedConfig;
12.
On the form create two more buttons.
Button. Name: btnOpenIniFile Text: Open INI
Button. Name: btnSaveIniFile Text: Save INI
13.
Enter the code for the Open INI buttons click event (btnOpenIniFile).
private void btnOpenIniFile_Click(object sender, EventArgs e) {
using(OpenFileDialog OpenFileIni = new OpenFileDialog()) {
var strSettingsDirectory = Directory.GetCurrentDirectory() + "\\Settings";
System.IO.Directory.CreateDirectory(strSettingsDirectory);
OpenFileIni.InitialDirectory = strSettingsDirectory;
OpenFileIni.Filter = "INI File|*.ini";
OpenFileIni.RestoreDirectory = true;
OpenFileIni.CheckFileExists = true;
OpenFileIni.CheckPathExists = true;
OpenFileIni.Title = "Open an INI Settings File";
if (OpenFileIni.ShowDialog() == DialogResult.OK)
{
_loadedConfig = new INIFile(OpenFileIni.FileName);
txtName.Text = _loadedConfig.HasSetting("UserSettings", "txtName") ? _loadedConfig["UserSettings"]["txtName"] : "";
txtSchool.Text = _loadedConfig.HasSetting("UserSettings", "txtSchool") ? _loadedConfig["UserSettings"]["txtSchool"] : "";
txtClass.Text = _loadedConfig.HasSetting("UserSettings", "txtClass") ? _loadedConfig["UserSettings"]["txtClass"] : "";
if (_loadedConfig["UserSettings"]["chkActiveStudent"] == "Checked")
{
chkActiveStudent.Checked = true;
}
else
{
chkActiveStudent.Checked = false;
}
}
}
}
14.
Enter the code for the Save INI buttons click event (btnSaveIniFile).
private void btnSaveIniFile_Click(object sender, EventArgs e)
{
using (SaveFileDialog SaveFileIni = new SaveFileDialog())
{
var strSettingsDirectory = Directory.GetCurrentDirectory() + "\\Settings";
System.IO.Directory.CreateDirectory(strSettingsDirectory);
SaveFileIni.InitialDirectory = strSettingsDirectory;
SaveFileIni.Filter = "INI File|*.ini";
SaveFileIni.Title = "Save an INI Settings File";
if (SaveFileIni.ShowDialog() == DialogResult.OK)
{
_loadedConfig = new INIFile(SaveFileIni.FileName);
_loadedConfig["UserSettings"]["txtName"] = txtName.Text;
_loadedConfig["UserSettings"]["txtSchool"] = txtSchool.Text;
_loadedConfig["UserSettings"]["txtClass"] = txtClass.Text;
if (chkActiveStudent.Checked == true)
{
_loadedConfig["UserSettings"]["chkActiveStudent"] = "Checked";
}
else
{
_loadedConfig["UserSettings"]["chkActiveStudent"] = "UnChecked";
}
_loadedConfig.Persist();
}
}
}
15.
That’s it. Run the app.
Make some changes to the text on the textbox controls. Save them using the Save INI button.
You will be prompted for a file name. It can be anything you like (but in this example I used the name of the person I setup in the first textbox.
You do not need to enter the ini file extension. You can change the location if you wish.
Make some more changes to the text in the textBoxes but do not save them.
Click on the Open INI button. Browse to the ini file you just saved and open it.
The text you just modified, without saving, should now be changed to the text you saved into the ini file.
Use OpenExeConfiguration function to read settings and then Add/Update key values before Save it back. Finally you can ConfigurationManager.RefreshSection to refresh settings of a particular section.
Example at Link
static void AddUpdateAppSettings(string key, string value)
{
try
{
var configFile = ConfigurationManager
.OpenExeConfiguration(ConfigurationUserLevel.None);
var settings = configFile.AppSettings.Settings;
if (settings[key] == null)
{
settings.Add(key, value);
}
else
{
settings[key].Value = value;
}
configFile.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection(configFile.AppSettings.SectionInformation.Name);
}
catch (ConfigurationErrorsException)
{
Console.WriteLine("Error writing app settings");
}
}
How save session in xamarin ios, i must use Xamarin.Auth?
I also need to be able to check if a session already exists when the app starts that way I skip the login page if they are already signed in
public class SettingsManager : ISettingsManager
{
public string PersonalFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
// Write Information to a Local File
public void WriteLocalFile(string FileName, string Data)
{
string filePath = Path.Combine(PersonalFolderPath, FileName);
File.WriteAllText(filePath, Data);
}
}
i found this thread https://forums.xamarin.com/discussion/117141/save-and-grab-session-id-and-other-data
To save session data, you can use Xamarin.Essentials
To save a value for a given key in preferences:
Preferences.Set("my_key", "my_value");
To retrieve a value from preferences or a default if not set:
var myValue = Preferences.Get("my_key", "default_value");
A common thing I do is name files by the current date/time. For instance, I'll name something 12-31-2016-08-46-01.jpg
This is great. It works well. But typing it every time is annoying, so I thought it useful to just write a small program that returns the output as a string. That was easy enough.
public class Program {
public static string Main() {
var strFilename = new DateTimeFilename();
return strFilename.Current();
}
public class DateTimeFilename {
public string Current () {
return // ... logic ... //
}
}
And then I add this program as a context menu option in the Windows registry.
Except that doesn't work. Apparently, I cannot return a string from the actual program.
So is there a way to get the string out of the program and into whatever my cursor is trying to type into at the time?
I would recommend that you work within Windows File Explorer and add a Send To option which does this operation and passes the current selected file name to the clipboard.
The following takes the selected filename and adds a custom date after the name, but before the extension, such as TheFile.20211123.txt:
static void Main(string[] args)
{
var name = $"{Path.GetFileNameWithoutExtension(args[0])}.{DateTime.Now.ToString("yyyyMMdd")}{Path.GetExtension(args[0])}";
// MessageBox.Show(name);
Clipboard.SetText(name);
}
Build the program and the create a file explorer short cut to the exe built. Then place the shortcut to this folder:
C:\Users\{username}\AppData\Roaming\Microsoft\Windows\SendTo
Then in File Explorer right click, select Send To and select the shortcut name you gave it.
Then paste the new name where ever you need it, for it resides in your clipboard.
I used RavenDB-Embedded 2.0.2230 in my application interacted with ASP .Net Web API in different assemblies.
When I set UseEmbeddedHttpServer = true on the document store, first time I send a request to RavenDB, it executes properly but when I try for the second time my application displays Raven Studio.
When I remove UseEmbeddedServer setting, my application runs without any problems.
My RavenDB is configured with the following codes in data tier :
this.documentStore = new EmbeddableDocumentStore
{
ConnectionStringName = "RavenDB",
UseEmbeddedHttpServer = true
}.Initialize();
and implementation of Web.config have these settings in the service tier :
<connectionStrings>
<add name="RavenDB" connectionString="DataDir=~\App_Data\RavenDatabase" />
</connectionStrings>
Is there a setting I missed?
Is there any settings I need to apply to point Raven Studio to a different port?
The only way I could reproduce the experience you describe is by intentionally creating a port conflict. By default, RavenDB's web server hosts on port 8080, so if you are not changing raven's port, then you must be hosting your WebApi application on port 8080. If this is not the case, please let me know in comments, but I will assume that it is so.
All you need to do to change the port Raven uses is to modify the port value before calling Initialize method.
Add this RavenConfig.cs file to your App_Startup folder:
using Raven.Client;
using Raven.Client.Embedded;
namespace <YourNamespace>
{
public static class RavenConfig
{
public static IDocumentStore DocumentStore { get; private set; }
public static void Register()
{
var store = new EmbeddableDocumentStore
{
UseEmbeddedHttpServer = true,
DataDirectory = #"~\App_Data\RavenDatabase",
// or from connection string if you wish
};
// set whatever port you want raven to use
store.Configuration.Port = 8079;
store.Initialize();
this.DocumentStore = store;
}
public static void Cleanup()
{
if (DocumentStore == null)
return;
DocumentStore.Dispose();
DocumentStore = null;
}
}
}
Then in your Global.asax.cs file, do the following:
protected void Application_Start()
{
// with your other startup registrations
RavenConfig.Register();
}
protected void Application_End()
{
// for a clean shutdown
RavenConfig.Cleanup();
}
When you enable the HttpServer in an EmbeddableDocumentStore ravenDB "hijacks" the webapplication and starts listening on the same port that the application is running.
Oren Eini:
When you use UseEmbeddedHttpServer from inside IIS, it takes the port
from IIS. You need to set the value again
on https://groups.google.com/forum/?fromgroups=#!topic/ravendb/kYVglEoMncw
The only way to prevent it is either turn-ff the raven http-server or assign it to a different port
int ravenPort = 8181;
NonAdminHttp.EnsureCanListenToWhenInNonAdminContext(ravenPort);
var ds = new EmbeddableDocumentStore {
DataDirectory = [DataFolder],
UseEmbeddedHttpServer = true,
Configuration = {Port = ravenPort}
};
I have written a windows service in C#. The requirement at the beginning was that I should be running only one instance of that service, but that has changed and now I need multiple instances. This is why I need to change the service name according to the configuration file.
What would be the best way to make it register with the correct name ? Should I write another tool to do it? Can I just read the name from App.config file and set it in the service and installer classes accordingly ?
PS> I do not really understand how that thing with names work - one should set names in service and installer classes, but then when installing with installutil.exe or even powershell new-service the name also should be specified. Does that have to be the same? Or one overrides another?
You can simply read it from the app.config and set it in the installer classes.
Normally, a class that inherits from Installer is automatically created. It contains a member of type System.ServiceProcess.ServiceInstaller, most likely named serviceProcessInstaller1. This has a property ServiceName you can set. Additionally, you need to set the ServiceName property of the ServiceBase derived class to the same value.
In a default implementation, these are set to constant values in the respective InitializeComponent methods, but there is no reason to stick with this. It can be done dynamically without problems.
I though I'd add my 2 cents since I ran into this. I have a file called "ProjectInstaller.cs" with designer and resources under it. Opening it up in design shows MyServiceInstaller and MyProjectInstaller as items on the design surface. I was able to change the names in the ProjectInstaller() constructor, and manually loaded the config file from the module directory:
public ProjectInstaller()
{
InitializeComponent();
var config = ConfigurationManager.OpenExeConfiguration(this.GetType().Assembly.Location);
if (config.AppSettings.Settings["ServiceName"] != null)
{
this.MyServiceInstaller.ServiceName = config.AppSettings.Settings["ServiceName"].Value;
}
if (config.AppSettings.Settings["DisplayName"] != null)
{
this.MyServiceInstaller.DisplayName = config.AppSettings.Settings["DisplayName"].Value;
}
}
In the same vein as Jason Goemaat's answer, this is how you would loop through all available installers in your project, which saves you the time of being sure you added each new service to this class. In my project, I have a total of 12 services (and we add a new one here and there), and we wanted them grouped together by the instance name, so SVC (Instance 1) Service XX and SVC (Instance 1) Service YY were next to each other when viewed in the services snap-in console.
public ProjectInstaller()
{
InitializeComponent();
var config = ConfigurationManager.OpenExeConfiguration(this.GetType().Assembly.Location);
string instanceName = config.AppSettings.Settings["Installer_NamedInstanceName"].Value;
string instanceID = config.AppSettings.Settings["Installer_NamedInstanceID"].Value;
bool usesNamedInstance = !string.IsNullOrWhiteSpace(instanceName) && !string.IsNullOrWhiteSpace(instanceID);
if (usesNamedInstance)
{
foreach (var installer in this.Installers)
{
if (installer is ServiceInstaller)
{
var ins = (ServiceInstaller)installer;
ins.ServiceName = ins.ServiceName + "-" + instanceID;
// Want the service to be named SVC (Instance Name) Audit Log Blah Blah Service
ins.DisplayName = ins.DisplayName.Replace("SVC ", "SVC (" + instanceName + ") ");
}
}
}
}
HOWEVER, there is something else that you need to do - When initializing the service, you must also change the service name, otherwise you'll get an error along the lines of "The executable doesn't implement the service". I did this by implementing the following code in Program.cs:
internal static void HandleCustomServiceName(ServiceBase sbase)
{
if (!string.IsNullOrWhiteSpace(customInstanceName))
{
sbase.ServiceName = sbase.ServiceName + "-" + customInstanceName;
}
}
Then, in the constructor of each service:
public SystemEventWatcher()
{
InitializeComponent();
Program.HandleCustomServiceName(this);
}
I've upvoted Jason's answer for paving the way to implementing this in my own project. Thanks!