My app is split up into a configuration tool which writes the configuration and a viewer which just reads and uses settings from the configuration.
What techniques for storing the properties would would be recommended in this scenario? Would XML for the different categories be a good idea?
The apps are developing in C#, on .NET 3.5 and using WinForms.
I would have a shared assembly, which contains your settings class. You can then serialize/deserialize this class to a common place on the hard drive:
[XmlRoot()]
public class Settings
{
private static Settings instance = new Settings();
private Settings() {}
/// <summary>
/// Access the Singleton instance
/// </summary>
[XmlElement]
public static Settings Instance
{
get
{
return instance;
}
}
/// <summary>
/// Gets or sets the height.
/// </summary>
/// <value>The height.</value>
[XmlAttribute]
public int Height { get; set; }
/// <summary>
/// Main window status (Maximized or not)
/// </summary>
[XmlAttribute]
public FormWindowState WindowState
{
get;
set;
}
/// <summary>
/// Gets or sets a value indicating whether this <see cref="Settings"/> is offline.
/// </summary>
/// <value><c>true</c> if offline; otherwise, <c>false</c>.</value>
[XmlAttribute]
public bool IsSomething
{
get;
set;
}
/// <summary>
/// Save setting into file
/// </summary>
public static void Serialize()
{
// Create the directory
if (!Directory.Exists(AppTmpFolder))
{
Directory.CreateDirectory(AppTmpFolder);
}
using (TextWriter writer = new StreamWriter(SettingsFilePath))
{
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
serializer.Serialize(writer, Settings.Instance);
}
}
/// <summary>
/// Load setting from file
/// </summary>
public static void Deserialize()
{
if (!File.Exists(SettingsFilePath))
{
// Can't find saved settings, using default vales
SetDefaults();
return;
}
try
{
using (XmlReader reader = XmlReader.Create(SettingsFilePath))
{
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
if (serializer.CanDeserialize(reader))
{
Settings.instance = serializer.Deserialize(reader) as Settings;
}
}
}
catch (System.Exception)
{
// Failed to load some data, leave the settings to default
SetDefaults();
}
}
}
Your xml file will then look like this:
<?xml version="1.0" encoding="utf-8"?>
<Settings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Height="738" WindowState="Maximized" IsSomething="false" >
</Settings>
XML would seem the ideal choice for this.
In WinForms user settings are persisted via XML so you have all the classes and helper methods you need.
Related
In a nutshell:
I have a list with items named Categories. For each of those items in the list Categories I have a xml file:
System.IO.File.Create(Categories[listPicker.SelectedIndex] + ".xml");
The created item is serialized into a xml file with the name of the selected index.
The problem:
The problem is that for each item in categories an xml file needs to be deserialized to a list, because each object of categories must be another list because it also contains items.
But there does not exist a list for deserialization of the xml file:
Deserialization:
Serialize.Deserialize(Variable list name , Categories[1]+".xml");
So how do i dynamically create lists or can you provide a better solution to this problem?
Even if each list has a different name, the structure of the content is the same. Text/Description and Value.
I would create a class for the Item. Something like
public class ComboItem{
public string Value {get; set;}
public string Text {get; set;}
}
Then I would create another class for the List of ComboItem that each XML File would have
public class ComboItemList
{
public ComboItemList()
{
ComboItems = new List<ComboItem>();
}
[XmlArray("ComboItems"), XmlArrayItem("ComboItem")]
public List<ComboItem> ComboItems { get; set; }
}
I have a Serialize/Deserialize Helper. Something like
#region static T DeserializeObject( string xml, Encoding encoding )
/// <summary>
/// Deserialize an Xml String to an [object]
/// </summary>
/// <typeparam name="T">Object Type to Deserialize</typeparam>
/// <param name="xml">Xml String to Deserialize</param>
/// <param name="encoding">System.Text.Encoding Type</param>
/// <returns>Default if Exception, Deserialize object if successful</returns>
/// <example>
/// // UTF-16 Deserialize
/// [object] = SerializationHelper<ObjectType>DeserializeObject( xml, Encoding.Unicode )
/// </example>
/// <example>
/// // UTF-8 Deserialize
/// [object] = SerializationHelper<ObjectType>DeserializeObject( xml, Encoding.UTF8 )
/// </example>
public static T DeserializeObject(string xml, Encoding encoding)
{
if (string.IsNullOrEmpty(xml)) { return default(T); }
try
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
using (MemoryStream memoryStream = new MemoryStream(encoding.GetBytes(xml)))
{
// No settings need modifying here
XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
using (XmlReader xmlReader = XmlReader.Create(memoryStream, xmlReaderSettings))
{
return (T)xmlSerializer.Deserialize(xmlReader);
}
}
}
catch
{
return default(T);
}
}
#endregion
/// <summary>
/// Deserialize an Xml String to an [object] with UTF8 as Encoding
/// </summary>
/// <param name="xml">Xml String to Deserialize</param>
/// <returns>Default if Exception, Deserialize object if successful</returns>
/// <example>
/// [object] = SerializationHelper<ObjectType>DeserializeObject( xml )
/// </example>
public static T DeserializeObjectFromFile(string filePath)
{
if (!File.Exists(filePath))
{
throw new FileNotFoundException(string.Format("The file {0}, don't exist.", filePath));
}
StreamReader sr = File.OpenText(filePath);
string xml = sr.ReadToEnd();
return DeserializeObject(xml, Encoding.UTF8);
}
that I would call like this
string filePath01 = "PATH TO FILE 01";
List<ComboItem> List01 = SerializationHelper<ComboItem>.DeserializeObjectFromFile(filePath01);
string filePath02 = "PATH TO FILE 02";
List<ComboItem> List02 = SerializationHelper<ComboItem>.DeserializeObjectFromFile(filePath02);
List01 and List02 would have the contents of File01 and File02. Repeat for every file you have.
With a better architecture, you could make some properties in base class, that could be singleton, and would only load each file, only once, increasing the performance.
Im new to stackoverflow but thought I should give its a try...
So what I'm trying to do is to save variables in a file which other programs can access... For example, I have a set-up application that takes care of all the setup data (ex. database information, strings, numbers, or booleans). What I thought was to save them to a file like Properties file or text file where another program could read them and modify that settings file. Could anyone please point me off in a proper direction?
Thanks
waco001
If you are working with C#, I would suggesting putting all your settings in a separate class and then use XmlSerialization to save it, that way you'll have functionality working with minimal amount of code, and you'll have your data saved in format easy to read by other applications.
There are multiple samples available how to do it, for example:
http://www.jonasjohn.de/snippets/csharp/xmlserializer-example.htm
Try to use App.config supported in visual studio project.
Create a settings class and serialize/deserialize it, also if you encapsulate your configuration in a different object this have the added benefit of managing it using a property gird, I usually do this with my configuration files, this is a little example:
using System;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace Generate.Test
{
/// <summary>
/// The configuration class.
/// </summary>
[Serializable, XmlRoot("generate-configuration")]
public class Configuration : ISerializable
{
#region Fields
private string inputPath = string.Empty;
private string outputPath = string.Empty;
private int maxCount = 0;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="Configuration" /> class.
/// </summary>
public Configuration()
{
}
#endregion
#region Properties
/// <summary>
/// Gets or sets the output path.
/// </summary>
/// <value>
/// The output path.
/// </value>
[XmlElement("output-path")]
public string OutputPath
{
get { return this.outputPath; }
set { this.outputPath = value; }
}
/// <summary>
/// Gets or sets the input path.
/// </summary>
/// <value>
/// The input path.
/// </value>
[XmlElement("input-path")]
public string InputPath
{
get { return this.inputPath; }
set { this.inputPath = value; }
}
/// <summary>
/// Gets or sets the max count.
/// </summary>
/// <value>
/// The max count.
/// </value>
[XmlElement("max-count")]
public int MaxCount
{
get { return this.maxCount; }
set { this.maxCount = value; }
}
#endregion
#region ISerializable Members
/// <summary>
/// Gets the object data.
/// </summary>
/// <param name="info">The info.</param>
/// <param name="context">The context.</param>
/// <exception cref="System.ArgumentNullException">thrown when the info parameter is empty.</exception>
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info == null)
throw new System.ArgumentNullException("info");
info.AddValue("output-path", this.OutputPath);
info.AddValue("input-path", this.InputPath);
info.AddValue("max-count", this.MaxCount);
}
#endregion
}
}
So to deserialize (_configurationPath is the path of the xml where the config is stored):
if (File.Exists(_configurationPath))
{
try
{
XmlSerializer serializer = new XmlSerializer(typeof(Configuration));
Stream stream = new FileStream(_configurationPath, FileMode.Open, FileAccess.Read);
Configuration config = (Configuration)serializer.Deserialize(stream);
_inputPath = config.InputPath;
_outputPath = config.OutputPath;
_maxCount = config.MaxCount;
}
catch (Exception exception)
{
Console.WriteLine("Error cargando el archivo de configuraciĆ³n '{0}':\n{1}", _configurationPath, exception);
}
}
And to serialize:
Configuration configuration = new Configuration(); // Create the object
// Set the values
configuration.InputPath = #".\input";
configuration.OutputPath = #".\output";
configuration.MaxCount = 1000;
// Serialize
XmlSerializer serializer = new XmlSerializer(typeof(Configuration));
Stream stream = new FileStream(_configurationPath, FileMode.Open, FileAccess.Write);
serializer.Serialize(stream, configuration);
Hope it helps.
The typical method would be to create an XmlDocument, fill it with aptly named nodes and attributes and write it out via Save(). This has the advantage, that most other environments are able to read XML and parse it.
Another "lingua franca" is JSON, which can easily be written via JSON.NET and is "understood" by most other environments.
If all you want is share data between applications, you should look into WCF.
Or you can use existing .NET API for XML to both create and parse data. Then use system IO to store it into hard drive.
I'm developing an application using C# in Visual Studio. This is my first C# application which will use a local database and I am therefore unsure exactly how this is done.
I have been following this article from codeguru.
I have declared my entities, all of which are currently just inheriting from this:
public class Reference
{
/// <summary>
/// ID of the reference.
/// </summary>
public int Id { get; set; }
/// <summary>
/// Reference to the element in theTVDB.
/// </summary>
public int TheTVDBId { get; set; }
/// <summary>
/// Whether or not the reference has been marked as watched.
/// </summary>
public bool IsWatched { get; set; }
}
I have also declared my DbContext as the following:
public class Library : DbContext
{
/// <summary>
/// Constructor using the base constructor.
/// This constructor names the database "Library".
/// </summary>
public Library() : base("Library")
{
}
/// <summary>
/// Set of TVSeriesReferences stored in the database.
/// </summary>
public DbSet<TVSeriesReference> TVSeriesReferences { get; set; }
/// <summary>
/// Set of SeasonReferences stored in the database.
/// </summary>
public DbSet<SeasonReference> SeasonReferences { get; set; }
/// <summary>
/// Set of EpisodeReferences stored in the database.
/// </summary>
public DbSet<EpisodeReference> EpisodeReferences { get; set; }
}
I am trying to store entities in the database doing the following:
Library db = new Library();
TVSeriesReference reference1 = new TVSeriesReference();
reference1.TheTVDBId = 1234;
reference1.IsWatched = true;
db.TVSeriesReferences.Add(reference1);
TVSeriesReference reference2 = new TVSeriesReference();
reference2.TheTVDBId = 8000;
db.TVSeriesReferences.Add(reference2);
int i = db.SaveChanges();
All of this seems to work. At least, I get no errors and i is 2 on every run.
The problem is that the database (which is named "Library") does not show up anywhere. Actually, I don't even have that "Object Explorer" view and I can't seem to find it.
As the database doesn't show up, I am unsure whether or not this is working and if my data is actually stored.
Does anyone know what I am doing wrong or if I am missing something?
I seem to have solved this problem.
I did the following:
In the Server Explorer, I right clicked the Data Connections, chose "Add Connection..." and created a Microsoft SQL Server. I set the server name to .\SQLEXPRESS and the database name to Library.
I then added the following to app.config:
It seems to work now.
<connectionStrings>
<add name="Library"
providerName="System.Data.SqlClient"
connectionString="Data Source=.\SQLEXPRESS;Database=Library;Trusted_Connection=true;" />
</connectionStrings>
I was using Application Settings (as part of Visual Studio) but can't seem to get the other app using the settings from the original app.
Can someone help with storing a few string variables between two apps in .net c#?
EDIT: seems I need to add a reference to my first app from the second app to access the Properties.Default settings - how do I do this?
if you want to share a config between to projects you can just add the file from the other project 'as a link': Right click on the project >> select 'Add existing file' >> navigate to the app.config file >> click the dropdown next to the add button and select add as a link.
or
if you want to share a config between two apps this is the method
I would have a shared assembly, which contains your settings class. You can then serialize/deserialize this class to a common place on the hard drive:
[XmlRoot()]
public class Settings
{
private static Settings instance = new Settings();
private Settings() {}
/// <summary>
/// Access the Singleton instance
/// </summary>
[XmlElement]
public static Settings Instance
{
get
{
return instance;
}
}
/// <summary>
/// Gets or sets the height.
/// </summary>
/// <value>The height.</value>
[XmlAttribute]
public int Height { get; set; }
/// <summary>
/// Main window status (Maximized or not)
/// </summary>
[XmlAttribute]
public FormWindowState WindowState
{
get;
set;
}
/// <summary>
/// Gets or sets a value indicating whether this <see cref="Settings"/> is offline.
/// </summary>
/// <value><c>true</c> if offline; otherwise, <c>false</c>.</value>
[XmlAttribute]
public bool IsSomething
{
get;
set;
}
/// <summary>
/// Save setting into file
/// </summary>
public static void Serialize()
{
// Create the directory
if (!Directory.Exists(AppTmpFolder))
{
Directory.CreateDirectory(AppTmpFolder);
}
using (TextWriter writer = new StreamWriter(SettingsFilePath))
{
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
serializer.Serialize(writer, Settings.Instance);
}
}
/// <summary>
/// Load setting from file
/// </summary>
public static void Deserialize()
{
if (!File.Exists(SettingsFilePath))
{
// Can't find saved settings, using default vales
SetDefaults();
return;
}
try
{
using (XmlReader reader = XmlReader.Create(SettingsFilePath))
{
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
if (serializer.CanDeserialize(reader))
{
Settings.instance = serializer.Deserialize(reader) as Settings;
}
}
}
catch (System.Exception)
{
// Failed to load some data, leave the settings to default
SetDefaults();
}
}
}
Your xml file will then look like this:
<?xml version="1.0" encoding="utf-8"?>
<Settings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Height="738" WindowState="Maximized" IsSomething="false" >
</Settings>
If you want the same user to use the same settings for both apps OR you want all users to share the same settings, you have a couple of choices besides the standard appsettings:
1) Store the data in the registry. You could either make the settings user specific or global to the machine.
2) Store a structured file, such as an XML file, containing the settings in one of the standard directories: Environment.SpecialFolder.CommonApplicationData for all users or Environment.SpecialFolder.ApplicationData for a single user. This would be the approach I would use.
I have the following ExportMetaData attributes set on my class:
[Export(typeof(IDocumentViewer))]
[ExportMetadata("Name", "MyViewer")]
[ExportMetadata("SupportsEditing", true)]
[ExportMetadata("Formats", DocFormat.DOC, IsMultiple = true)]
[ExportMetadata("Formats", DocFormat.DOCX, IsMultiple = true)]
[ExportMetadata("Formats", DocFormat.RTF, IsMultiple = true)]
I also have a supporting interface:
public interface IDocumentViewerMetaData {
/// <summary>
/// Gets the format.
/// </summary>
/// <value>The format.</value>
IEnumerable<DocFormat> Formats { get; }
/// <summary>
/// Gets the name of the viewer
/// </summary>
/// <value>The name.</value>
string Name { get; }
/// <summary>
/// Gets a value indicating whether this viewer supports editing
/// </summary>
/// <value><c>true</c> if [supports editing]; otherwise, <c>false</c>.</value>
bool SupportsEditing { get; }
}
And of course my ImportMany:
[ImportMany(typeof(IDocumentViewer))]
public IEnumerable<Lazy<IDocumentViewer, IDocumentViewerMetaData>> _viewers { get; set; }
What I would like to do is use a strongly-typed attribute class instead of using the ExportMetaData attribute. I have not figured out a way to do this while also supporting single values (Name, SupportsEditing, in the example above).
I envision doing something similiar the following (or whatever is suggested as best):
[Export(typeof(IDocumentViewer))]
[DocumentViewerMetadata(Name = "MyViewer")]
[DocumentViewerMetadata(SupportsEditing = true)]
[DocumentViewerMetadata(Format = DocFormat.DOC)]
[DocumentViewerMetadata(Format = DocFormat.DOCX)]
I am fairly certain that there IS a way to do this, I just haven't found the right way to connect the dots. :)
You can subclass the ExportAttribute with your own implementation, and decorate it with a MetadataAttribute to allow MEF to use its properties to project the metadata proxy it uses during composition:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property),
MetadataAttribute]
public class ExportDocumentViewerAttribute : ExportAttribute, IDocumentViewerMetadata
{
public ExportDocumentViewer(string name, bool supportsEditing, params DocFormat[] formats)
: base(typeof(IDocumentViewer))
{
if (string.IsNullOrEmpty(name))
throw new ArgumentException("Export requires a name", "name");
Name = name;
SupportsEditing = supportsEditing;
Formats = formats ?? Enumerable.Empty<DocFormat>();
}
public string Name { get; private set; }
public bool SupportsEditing { get; private set; }
public IEnumerable<DocFormat> Formats { get; private set; }
}
[ExportDocumentViewer("Word", true, DocFormat.DOC, DocFormat.DOCX)]
public WordDocumentViewer : IDocumentViewer
{
// Stuff
}
Note you don't actually need to decorate it with your IDocumentViewerMetadata contract, as MEF will project it regardless, I just prefer to so that I know if I make changes to the metadata contract, that my custom export attribute conforms.