Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 12 months ago.
Improve this question
I'm writing an application that takes user data and stores it locally for use later. The application will be started and stopped fairly often, and I'd like to make it save/load the data on application start/end.
It'd be fairly straightforward if I used flat files, as the data doesn't really need to be secured (it'll only be stored on this PC). The options I believe are thus:
Flat files
XML
SQL DB
Flat files require a bit more effort to maintain (no built in classes like with XML), however I haven't used XML before, and SQL seems like overkill for this relatively easy task.
Are there any other avenues worth exploring? If not, which of these is the best solution?
Edit: To add a little more data to the problem, basically the only thing I'd like to store is a Dictionary that looks like this
Dictionary<string, List<Account>>
where Account is another custom type.
Would I serialize the dict as the xmlroot, and then the Account type as attributes?
Update 2:
So it's possible to serialize a dictionary. What makes it complicated is that the value for this dict is a generic itself, which is a list of complex data structures of type Account. Each Account is fairly simple, it's just a bunch of properties.
It is my understanding that the goal here is to try and end up with this:
<Username1>
<Account1>
<Data1>data1</Data1>
<Data2>data2</Data2>
</Account1>
</Username1>
<Username2>
<Account1>
<Data1>data1</Data1>
<Data2>data2</Data2>
</Account1>
<Account2>
<Data1>data1</Data1>
<Data2>data2</Data2>
</Account2>
</Username2>
As you can see the heirachy is
Username (string of dict) >
Account (each account in the List) >
Account data (ie class properties).
Obtaining this layout from a Dictionary<Username, List<Account>> is the tricky bit, and the essence of this question.
There are plenty of 'how to' responses here on serialisation, which is my fault since I didn't make it clearer early on, but now I'm looking for a definite solution.
I'd store the file as JSON. Since you're storing a dictionary which is just a name/value pair list then this is pretty much what json was designed for.
There a quite a few decent, free .NET json libraries - here's one but you can find a full list on the first link.
It really depends on what you're storing. If you're talking about structured data, then either XML or a very lightweight SQL RDBMS like SQLite or SQL Server Compact Edition will work well for you. The SQL solution becomes especially compelling if the data moves beyond a trivial size.
If you're storing large pieces of relatively unstructured data (binary objects like images, for example) then obviously neither a database nor XML solution are appropriate, but given your question I'm guessing it's more of the former than the latter.
All of the above are good answers, and generally solve the problem.
If you need an easy, free way to scale to millions of pieces of data, try out the ESENT Managed Interface project on GitHub or from NuGet.
ESENT is an embeddable database storage engine (ISAM) which is part of Windows. It provides reliable, transacted, concurrent, high-performance data storage with row-level locking, write-ahead logging and snapshot isolation. This is a managed wrapper for the ESENT Win32 API.
It has a PersistentDictionary object that is quite easy to use. Think of it as a Dictionary() object, but it is automatically loaded from and saved to disk without extra code.
For example:
/// <summary>
/// Ask the user for their first name and see if we remember
/// their last name.
/// </summary>
public static void Main()
{
PersistentDictionary<string, string> dictionary = new PersistentDictionary<string, string>("Names");
Console.WriteLine("What is your first name?");
string firstName = Console.ReadLine();
if (dictionary.ContainsKey(firstName))
{
Console.WriteLine("Welcome back {0} {1}", firstName, dictionary[firstName]);
}
else
{
Console.WriteLine("I don't know you, {0}. What is your last name?", firstName);
dictionary[firstName] = Console.ReadLine();
}
To answer George's question:
Supported Key Types
Only these types are supported as
dictionary keys:
Boolean Byte Int16 UInt16 Int32 UInt32
Int64 UInt64 Float
Double Guid DateTime TimeSpan String
Supported Value Types
Dictionary values can be any of the
key types, Nullable versions of the
key types, Uri, IPAddress or a
serializable structure. A structure is
only considered serializable if it
meets all these criteria:
• The structure is marked as
serializable • Every member of the
struct is either:
1. A primitive data type (e.g. Int32)
2. A String, Uri or IPAddress
3. A serializable structure.
Or, to put it another way, a
serializable structure cannot contain
any references to a class object. This
is done to preserve API consistency.
Adding an object to a
PersistentDictionary creates a copy of
the object though serialization.
Modifying the original object will not
modify the copy, which would lead to
confusing behavior. To avoid those
problems the PersistentDictionary will
only accept value types as values.
Can Be Serialized [Serializable] struct Good {
public DateTime? Received;
public string Name;
public Decimal Price;
public Uri Url; }
Can’t Be Serialized [Serializable] struct Bad {
public byte[] Data; // arrays aren’t supported
public Exception Error; // reference object }
XML is easy to use, via serialization. Use Isolated storage.
See also How to decide where to store per-user state? Registry? AppData? Isolated Storage?
public class UserDB
{
// actual data to be preserved for each user
public int A;
public string Z;
// metadata
public DateTime LastSaved;
public int eon;
private string dbpath;
public static UserDB Load(string path)
{
UserDB udb;
try
{
System.Xml.Serialization.XmlSerializer s=new System.Xml.Serialization.XmlSerializer(typeof(UserDB));
using(System.IO.StreamReader reader= System.IO.File.OpenText(path))
{
udb= (UserDB) s.Deserialize(reader);
}
}
catch
{
udb= new UserDB();
}
udb.dbpath= path;
return udb;
}
public void Save()
{
LastSaved= System.DateTime.Now;
eon++;
var s= new System.Xml.Serialization.XmlSerializer(typeof(UserDB));
var ns= new System.Xml.Serialization.XmlSerializerNamespaces();
ns.Add( "", "");
System.IO.StreamWriter writer= System.IO.File.CreateText(dbpath);
s.Serialize(writer, this, ns);
writer.Close();
}
}
I recommend XML reader/writer class for files because it is easily serialized.
Serialization in C#
Serialization (known as pickling in
python) is an easy way to convert an
object to a binary representation that
can then be e.g. written to disk or
sent over a wire.
It's useful e.g. for easy saving of settings to a file.
You can serialize your own classes if
you mark them with [Serializable]
attribute. This serializes all members
of a class, except those marked as
[NonSerialized].
The following is code to show you how to do this:
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
namespace ConfigTest
{ [ Serializable() ]
public class ConfigManager
{
private string windowTitle = "Corp";
private string printTitle = "Inventory";
public string WindowTitle
{
get
{
return windowTitle;
}
set
{
windowTitle = value;
}
}
public string PrintTitle
{
get
{
return printTitle;
}
set
{
printTitle = value;
}
}
}
}
You then, in maybe a ConfigForm, call your ConfigManager class and Serialize it!
public ConfigForm()
{
InitializeComponent();
cm = new ConfigManager();
ser = new XmlSerializer(typeof(ConfigManager));
LoadConfig();
}
private void LoadConfig()
{
try
{
if (File.Exists(filepath))
{
FileStream fs = new FileStream(filepath, FileMode.Open);
cm = (ConfigManager)ser.Deserialize(fs);
fs.Close();
}
else
{
MessageBox.Show("Could not find User Configuration File\n\nCreating new file...", "User Config Not Found");
FileStream fs = new FileStream(filepath, FileMode.CreateNew);
TextWriter tw = new StreamWriter(fs);
ser.Serialize(tw, cm);
tw.Close();
fs.Close();
}
setupControlsFromConfig();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
After it has been serialized, you can then call the parameters of your config file using cm.WindowTitle, etc.
If your collection gets too big, I have found that Xml serialization gets quite slow. Another option to serialize your dictionary would be "roll your own" using a BinaryReader and BinaryWriter.
Here's some sample code just to get you started. You can make these generic extension methods to handle any type of Dictionary, and it works quite well, but is too verbose to post here.
class Account
{
public string AccountName { get; set; }
public int AccountNumber { get; set; }
internal void Serialize(BinaryWriter bw)
{
// Add logic to serialize everything you need here
// Keep in synch with Deserialize
bw.Write(AccountName);
bw.Write(AccountNumber);
}
internal void Deserialize(BinaryReader br)
{
// Add logic to deserialize everythin you need here,
// Keep in synch with Serialize
AccountName = br.ReadString();
AccountNumber = br.ReadInt32();
}
}
class Program
{
static void Serialize(string OutputFile)
{
// Write to disk
using (Stream stream = File.Open(OutputFile, FileMode.Create))
{
BinaryWriter bw = new BinaryWriter(stream);
// Save number of entries
bw.Write(accounts.Count);
foreach (KeyValuePair<string, List<Account>> accountKvp in accounts)
{
// Save each key/value pair
bw.Write(accountKvp.Key);
bw.Write(accountKvp.Value.Count);
foreach (Account account in accountKvp.Value)
{
account.Serialize(bw);
}
}
}
}
static void Deserialize(string InputFile)
{
accounts.Clear();
// Read from disk
using (Stream stream = File.Open(InputFile, FileMode.Open))
{
BinaryReader br = new BinaryReader(stream);
int entryCount = br.ReadInt32();
for (int entries = 0; entries < entryCount; entries++)
{
// Read in the key-value pairs
string key = br.ReadString();
int accountCount = br.ReadInt32();
List<Account> accountList = new List<Account>();
for (int i = 0; i < accountCount; i++)
{
Account account = new Account();
account.Deserialize(br);
accountList.Add(account);
}
accounts.Add(key, accountList);
}
}
}
static Dictionary<string, List<Account>> accounts = new Dictionary<string, List<Account>>();
static void Main(string[] args)
{
string accountName = "Bob";
List<Account> newAccounts = new List<Account>();
newAccounts.Add(AddAccount("A", 1));
newAccounts.Add(AddAccount("B", 2));
newAccounts.Add(AddAccount("C", 3));
accounts.Add(accountName, newAccounts);
accountName = "Tom";
newAccounts = new List<Account>();
newAccounts.Add(AddAccount("A1", 11));
newAccounts.Add(AddAccount("B1", 22));
newAccounts.Add(AddAccount("C1", 33));
accounts.Add(accountName, newAccounts);
string saveFile = #"C:\accounts.bin";
Serialize(saveFile);
// clear it out to prove it works
accounts.Clear();
Deserialize(saveFile);
}
static Account AddAccount(string AccountName, int AccountNumber)
{
Account account = new Account();
account.AccountName = AccountName;
account.AccountNumber = AccountNumber;
return account;
}
}
A fourth option to those you mention are binary files. Although that sounds arcane and difficult, it's really easy with the serialization API in .NET.
Whether you choose binary or XML files, you can use the same serialization API, although you would use different serializers.
To binary serialize a class, it must be marked with the [Serializable] attribute or implement ISerializable.
You can do something similar with XML, although there the interface is called IXmlSerializable, and the attributes are [XmlRoot] and other attributes in the System.Xml.Serialization namespace.
If you want to use a relational database, SQL Server Compact Edition is free and very lightweight and based on a single file.
Just finished coding data storage for my current project. Here is my 5 cents.
I started with binary serialization. It was slow (about 30 sec for load of 100,000 objects) and it was creating a pretty big file on the disk as well. However, it took me a few lines of code to implement and I got my all storage needs covered.
To get better performance I moved on custom serialization. Found FastSerialization framework by Tim Haynes on Code Project. Indeed it is a few times faster (got 12 sec for load, 8 sec for save, 100K records) and it takes less disk space. The framework is built on the technique outlined by GalacticJello in a previous post.
Then I moved to SQLite and was able to get 2 sometimes 3 times faster performance – 6 sec for load and 4 sec for save, 100K records. It includes parsing ADO.NET tables to application types. It also gave me much smaller file on the disk. This article explains how to get best performance out of ADO.NET: http://sqlite.phxsoftware.com/forums/t/134.aspx. Generating INSERT statements is a very bad idea. You can guess how I came to know about that. :) Indeed, SQLite implementation took me quite a bit of time plus careful measurement of time taking by pretty much every line of the code.
The first thing I'd look at is a database. However, serialization is an option. If you go for binary serialization, then I would avoid BinaryFormatter - it has a tendency to get angry between versions if you change fields etc. Xml via XmlSerialzier would be fine, and can be side-by-side compatible (i.e. with the same class definitions) with protobuf-net if you want to try contract-based binary serialization (giving you a flat file serializer without any effort).
If your data is complex, high in quantity or you need to query it locally then object databases might be a valid option. I'd suggest looking at Db4o or Karvonite.
A lot of the answers in this thread attempt to overengineer the solution. If I'm correct, you just want to store user settings.
Use an .ini file or App.Config file for this.
If I'm wrong, and you are storing data that is more than just settings, use a flat text file in csv format. These are fast and easy without the overhead of XML. Folks like to poo poo these since they aren't as elegant, don't scale nicely and don't look as good on a resume, but it might be the best solution for you depending on what you need.
Without knowing what your data looks like, i.e. the complexity, size, etc...XML is easy to maintain and easily accessible. I would NOT use an Access database, and flat files are more difficult to maintain over the long haul, particularly if you are dealing with more than one data field/element in your file.
I deal with large flat-file data feeds in good quantities daily, and even though an extreme example, flat-file data is much more difficult to maintain than the XML data feeds I process.
A simple example of loading XML data into a dataset using C#:
DataSet reportData = new DataSet();
reportData.ReadXml(fi.FullName);
You can also check out LINQ to XML as an option for querying the XML data...
HTH...
I have done several "stand alone" apps that have a local data store. I think the best thing to use would be SQL Server Compact Edition (formerly known as SQLAnywhere).
It's lightweight and free. Additionally, you can stick to writing a data access layer that is reusable in other projects plus if the app ever needs to scale to something bigger like full blown SQL server, you only need to change the connection string.
Depending on the compelexity of your Account object, I would recomend either XML or Flat file.
If there are just a couple of values to store for each account, you could store them on a properties file, like this:
account.1.somekey=Some value
account.1.someotherkey=Some other value
account.1.somedate=2009-12-21
account.2.somekey=Some value 2
account.2.someotherkey=Some other value 2
... and so forth. Reading from a properties file should be easy, as it maps directly to a string dictionary.
As to where to store this file, the best choise would be to store into AppData folder, inside a subfolder for your program. This is a location where current users will always have access to write, and it's kept safe from other users by the OS itself.
My first inclination is an access database. The .mdb files are stored locally, and can be encrypted if that is deemed necessary. Though XML or JSON would also work for many scenarios. Flat files I would only use for read only, non-search (forward read only) information. I tend to prefer csv format to set width.
It depends on the amount of data you are looking to store. In reality there's no difference between flat files and XML. XML would probably be preferable since it provides a structure to the document. In practice,
The last option, and a lot of applications use now is the Windows Registry. I don't personally recommend it (Registry Bloat, Corruption, other potential issues), but it is an option.
If you go the binary serialization route, Consider the speed at which a particular member of the datum needs to be accessed. If it is only a small collection, loading the whole file will make sense, but if it will be large, you might also consider an index file.
Tracking Account Properties/fields that are located at a specific address within the file can help you speed up access time, especially if you optimize that index file based on key usage. (possibly even when you write to disk.)
Keep it simple - as you said, a flat file is sufficient. Use a flat file.
This is assuming that you have analyzed your requirements correctly. I would skip the serializing as XML step, overkill for a simple dictionary. Same thing for a database.
In my experience in most cases JSON in a file is enough (mostly you need to store an array or an object or just a single number or string). I rarely need SQLite (which needs more time for setting it up and using it, most of the times it's overkill).
Related
I serialize all the objects contained in a list each time a new object is added (kind of an history if the application crashes).
Serialization is done within a millisecond when adding the first ~20 objects, but from now on, each newly added object is going to take longer and longer (if I add 10 more it can take 10 minutes to serialize).
As I said, it's kind of an history. So if I restart app, every object in the JSON file is added back to the list. Let's admit I had 20 objects before closing app.
Now I can add 20 more objects, so it will serialize 40 within a millisecond.
Once again, if I add even more objects, I'll have to close and restart app.
I don't understand why multiple serializations in the same instance of the app takes that long.
Here's the serialization code:
public static void SerializeAll()
{
string output = JsonConvert.SerializeObject(ListOfModelToSerialize, Formatting.Indented);
IO.StreamWriter writer = new IO.StreamWriter("A:\history.json");
writer.Write(output);
writer.Close();
}
Deserialization code:
public static List<ModelToSerialize> DeserializeAll()
{
if (IO.File.Exists("A:\history.json"))
{
string input = IO.File.ReadAllText("A:\history.json");
var result = JsonConvert.DeserializeObject<List<ModelToSerialize>>(input);
return result;
}
else
{
return new List<ModelToSerialize>();
}
}
And I only serialize 4 properties from my model. Here's the serialized model output:
{
"an_integer": 1,
"a_string": "...",
"a_list_of_string": [],
"another_list_of_string": []
}
UPDATE 1:
It seems like the integer (ID) I'm serializing is the problem.
In fact, this ID is not assigned at the model creation because it changes everytime a new object is added to the list, as the list is sorted alphabetically. So to get the ID, I do this:
[JsonProperty(PropertyName = "id")]
public int Id
{
get
{
if (_id > 0)
{
return _id;
}
else
{
int id = Properties.Settings.Default.PREVIOUS_MAX_ID + 1;
foreach (File file in _directory.Files)
{
if (file == this)
{
return id;
}
else if (file.Id == id)
{
id += 1;
}
}
return 0;
}
}
}
So the reason why it doesn't take longer to serialize the first 20 objects after the app restart is that the ID is directly assigned at deserialization.
So I have to adapt the ID retrieval.
UPDATE 2:
As the ID retrieval was the performance issue, I fixed it by assigning the ID to each object each time a new object is added.
Like that, when the object ID is called, there is no more iteration in the model.
The following block is my custom Add() method for my list of objects:
public new void Add(File file)
{
if (!base.Contains(file))
{
base.Add(file);
base.Sort(new Comparer());
for (int i = 0; i < Count; i++)
{
this[i].Id = Properties.Settings.Default.PREVIOUS_MAX_ID + i;
}
}
}
I added ~100 new objects to the current instance of the app, and serialization is not taking years anymore.
Serialization (JSON etc) is best when used to communicate a discrete bit of data from one medium to another, such as making network API calls. It can also be used to store data to disk as you are doing.
But it's not a great option when you are frequently updating that data because the most popular formats (JSON, XML) are not structured so that new data can just be appended to existing data. That's why it needs to be serialized every time. And so of course as the data gets larger serialization will take longer.
For your purpose I would suggest a database like SQLite. You could still serialize each individual row to JSON if the data doesn't lend itself well to columns, but you'll be able to append new data to the database without having to rewrite the old. And if you use transactions you can also ensure that the data keeps its integrity even if your app crashes.
For any kind of performance issue I would recommend to measure, ideally using a performance profiler that can tell you exactly what part of the code is slow.
Some general suggestions
You probably want to have a limit on how much history you keep. Otherwise there is a risk that your application will get slower and slower as you accumulate objects. This also lets you test worst case performance.
Use a faster serializer, while json.net is good, using some variant of binary serialization, like protobuf.net, typically results in less data and time (benchmark), at the cost of not being humanly readable. You might also consider a fast compressor like lz4 to reduce the file size and therefore disk-performance.
Change your model so you do not have to overwrite all data. Either serialize to different files, or use some serialization method that lets you append messages to the same file.
Limit save-frequency. You might not need to save history for each and every change, it might be sufficient to save every 5s or so.
If you have not already done so, ensure that at least saving data is done asynchronously so it does not block the UI thread. This might require some way to access your data in a thread safe manner so ensure it cannot change while it is being serialized.
So I am doing this c# program which basically is a coffee machine. Asks the user to register and adds the instance in a textfile, then login, then asks which coffee he wants from a provided list, and finally increments a property named "coffee points". The problem is that I have no idea how I am going to update the coffee points inside my textfile. I can get the coffee points and increment them by 1 and then print them in console, however, I dont know how to update just the coffee points in my textfile of a certain user.
Below is the code I am using to retrieve the coffee points of the logged in user and increment them by 1, and store them in the variable "newCoffeePoints".
int newCoffeePoints = 0;
for (int i = 0; i < customerList.Count; i++)
{
if (customerList[i].iUsername == cu2.iUsername)
{
customerList[i].iCoffeePoints += 1;
newCoffeePoints = customerList[i].iCoffeePoints;
break;
}
}
Well, for this exact purpose we have so many different types of databases such as Mongo, SQL etc.
But if you're trying to serialize/deserialize object and save it to a file among other types of serialization you might want to consider JSON format. The libarary Newtonsoft.js is what we (C# developers) usually use for that.
You could create a virtual structure that reflects what you need.
Since we might want to find object by key a Dictionary<TKey, TValue> collection suits much better than List<T>.
Do whatever operation you need to do with users in a Dictionary<key, value> and then serialize it to JSON and save it to disc using the File.WriteAllText(json) method.
Whether to do it after each update (so that if app crashes all the data is saved) or do it once when the app is about to finish execution will depend on your needs.
The field with dictionary could be something along the lines of:
// CKeyType here is a type of customer's id field such as int, string etc.
private static readonly CustomerDict = new Dictionary<CKeyType, Customer>();
You can easily solve this problem by using JSON and Newtonsoft Library. (Fabjan mentioned above)
Here is a tutorial link from Microsoft Virtual Academy that you can follow.
https://mva.microsoft.com/en-US/training-courses/introduction-to-json-with-c-12742?l=xxtX274UB_8805494542
I am looking for suggestions on how to best attack my problem.
I have a web application that will utilize a database and XML file as its data source.
Updating the DB is no issue, dealing with the XML file is.
First understand the web app is a bypass to a current(and bad performing production system). So there is no flexibility there.
So in case of the XML file the following steps will need to be performed if a user adds/update/delete a field.
Pull XML file from linux server
Parse XML file into POCOs for the UI
Recreate the XML file from the POCOs with the modifications
Push XML file to the linux server
The only good thing in my favor is that I won't have very many users using this app at a given time.
I would highly recommend looking at the DataContractSerializer for your serialization needs. Your objects would have to follow the same format as the XML, but there is no reason that you can't make those objects your model. Here is an example of marking up a POCO to serialize automatically to and from XML:
[DataContract]
public class Account
{
[DataMember, XmlAttribute]
public string Name { get; set; }
[DataMember]
public double Balance { get; set; }
}
And then you use the serialization code like this:
string serializedAccount = null;
XmlSerializer serializer = new XmlSerializer(typeof(Account));
using(StringWriter writer = new StringWriter())
{
serializer.Serialize(writer, myAccountObject);
serializedAccount = writer.ToString();
}
// serializedAccount should look something like this:
//
// <Account Name="MyName">
// <Balance>100</Balance>
// </Account>
//
// Each of the DataMember and DataContract attributes allow you to override
// names so that you can make them lower case, or provide a more meaningful
// name in your POCO.
Account deserializedAccount = null;
using(StringReader reader = new StringReader(serializedAccount))
{
deserializedAccount = serializer.DeSerialize(reader) as Account;
}
A couple things to keep in mind:
DataContract is an opt in policy. Members are ignored unless you explicitly mark them as ignored.
If you want to explicitly mark a field or property as ignored, use the [IgnoreDataMember] attribute. It can be handy even just for documentation purposes.
Nothing in the serializer prevents you from implementing INotifyPropertyChanged so all your properties can be bindable (handy for WPF)
If your XML format is not what you want to use as a model for your UI, you still may need to map properties in one object to properties in another object. This is still orders of magnitude easier than hand writing the XML reading/writing code yourself.
NOTE: if your server implements a proper SOAP web API, then WCF can take the WSDL and generate the bindings to the API and the objects that need to be serialized. There's a bit more work involved if it's a REST API, but that's also supported.
I have some fairly basic questions regarding the use of booksleeve in conjunction with protobuf-net. Now I have implemented a singleton class to manage the connections so I am reusing the same connection many times as recommended. Now I several questions regarding actual use of the combo:
What is the difference/importance of the "db" int and the "key" string?
How would I serialize a bunch of objects into a SortedSet/List using protobuf-net?
How would I deserialize a bunch of objects from a SortedSet/List using protobuf-net?
I was thinking that I should use the Range() method for retrieval:
public IList<T> RetrieveAllAsList()
{
var conn = RedisConnectionManager.Current.GetConnection();
conn.Open();
int length = (int)conn.Lists.GetLength(10, "idk").Result;
byte[][] data = conn.Lists.Range(10, "idk", 0, length-1).Result;
List<T> output = new List<T>();
for (int i = 0; i < data.Length; i++)
{
using (MemoryStream ms = new MemoryStream(data[i]))
{
output.Add(Serializer.Deserialize<T>(ms));
}
}
conn.Close(false);
return output;
}
I would appreciate any help in this matter. Thank you.
What is the difference/importance of the "db" int and the "key" string?
Redis allows you to partition your data into several databases. For example, on the stackexchange websites, you may store stackoverflow.com related stuff in db=0, and programmers.se.com related stuff in db = 1.
Within each database, you have key = value pairs. The key is always a String. The value can be one of the following five data types - String, List, Set, Sorted Set or a Map.
A traditional Redis client does not force you to provide the database number. If you don't provide one, it assumes db=0. But Booksleeve requires you to provide the database number. If you don't care, just pass 0 to all API calls.
The string key must be unique though, and is totally application specific. For example, to store a user object, the usual technique is to have a key like user:1190099, and the value as a Map with key=value pairs like {"name":"singlelabs", "id":1190099 ... }
How would I serialize a bunch of objects into a SortedSet/List using protobuf-net?
How would I deserialize a bunch of objects from a SortedSet/List using protobuf-net?
First, you need to decide whether you want to use protocol buffers or not.
Protocol Buffers can serialize/deserialize complex objects into a binary blob. This blob is opaque to Redis. In other words, you can set or get this binary blob, but you cannot use any other Redis features.
If you really want to use Redis' lists and sorted sets, you should use the APIs provided by BookSleeve. I haven't used Booksleeve, but the following two interfaces should explain how to insert data into a list / sortedset.
http://code.google.com/p/booksleeve/source/browse/BookSleeve/ISortedSetCommands.cs
http://code.google.com/p/booksleeve/source/browse/BookSleeve/IListCommands.cs
Sripathi already did a good job of explaining what the DB key is. The reason it is required is that BookSleeve works as a multiplexer, so of you are using a DB it needs to be passed to avoid race conditions when different callers are using different databases. Just pass 0 if you aren't using multiple databases.
Re serialization/deserialization - this is deliberately done separately, so that the caller can use the appropriate serialization for them - so BookSleeve only knows about strings and blobs. Your serialiazation code looks ok though.
The only critique I would have is that there is no need to get the length first. The intellisense should illustrate the usage - I expect passing -1 or int.MaxValue will list all the items without needing to get the length first (apologies for being vague, but I'm in a departure lounge). This avoids a network trip.
I have a console application that I am rebuilding from C to C#. This application has to be able to support the legacy method of storing information like parameters from a command-line and parameters from a file (called the system parameters) that customize each run. The system parameters file is in plain-text with a simple key-value structure.
My questions are:
Should I combine these different parameters into a single Configuration object?
How would I call this configuration object from the code to store parameters?
How would I call this configuration object from the code to retrieve parameters?
Should this object be strongly-typed?
I will need access to this structure from a lot of different places in the code. What is the most elegant way to retrieve the values in the object without passing the object itself around everywhere?
I have a feeling that it should be a single, strongly-typed object and that it should be an instantiated object that is retrieved from a repository with a static retrieval method however I really want validation of this method.
I would use a single configuration object like the following:
using System;
using System.IO;
using System.Reflection;
public sealed class Setting {
public static int FrameMax { get; set; }
public static string VideoDir { get; set; }
static readonly string SETTINGS = "Settings.ini";
static readonly Setting instance = new Setting();
Setting() {}
static Setting() {
string property = "";
string[] settings = File.ReadAllLines(SETTINGS);
foreach (string s in settings)
try {
string[] split = s.Split(new char[] { ':' }, 2);
if (split.Length != 2)
continue;
property = split[0].Trim();
string value = split[1].Trim();
PropertyInfo propInfo = instance.GetType().GetProperty(property);
switch (propInfo.PropertyType.Name) {
case "Int32":
propInfo.SetValue(null, Convert.ToInt32(value), null);
break;
case "String":
propInfo.SetValue(null, value, null);
break;
}
} catch {
throw new Exception("Invalid setting '" + property + "'");
}
}
}
Since this is a singleton, it will create one and only one instance of itself the first time a public static property is referenced from the Setting object.
When the object is created, it reads from the Settings.ini file. The settings file is a plain-text file with a simple key : value structure that might look like this:
FrameMax : 12
VideoDir : C:\Videos\Best
The object uses reflection to discover each property and to store its initial value. In this example, two properties have been defined:
public static int FrameMax { get; set; }
public static string VideoDir { get; set; }
The code as written handles Int32 and String types. By adding additional case statements to the switch statement, you could easily add support for types like Float and Decimal.
To change a setting, you would use something like:
Setting.FrameMax = 5;
To retrieve a setting, you would use something like:
if (Setting.FrameMax > 10) ...
You'll notice that all the properties are strongly-typed. Also, you don't have to pass the Setting object around, as all the Setting properties are static and always available everywhere.
I hope this idea is helpful.
I like using Settings. These can be generated automatically either by creating a settings file using the Add New File dialog box, or by adding a default settings file from project properties.
Each setting may be in user or application scope, which controls whether or not the user can change them or they are restricted to their default values. They are easily saved with the Save() method and loaded automatically into the static Default property.
This class seems to be for application or user-based settings. I'm looking for per-run settings. Would you still recommend using this class in that case? – x97mdr
Yes. If you have both user/application based settings and per-run settings you should use two different classes - the normal (saved) settings and the per-run settings.
As long as you don't save the per-run settings, you should be safe and settings are still quite easy to use. These are static settings though. If the same application run needs several instances - this is the wrong approach.
I find that whenever I have to deal with a legacy system, sticking with the old format almost always works best. Often times there are other people using the legacy formats for other tasks (like automation of the app, for example), so if you recode the way the application handles inputs, you might break other systems.
On the other hand, if you are pretty confident that you know all the people using the system, and they tell you that they don't care if you change these types of things, I would probably move everything to XML. Besides all the nice features of XML from an application point of view (like being in ASCII so it's easily modified by humans, being self-documenting, etc ...), XML is also time-saving, in that you don't have to write your own I/O or parser. There's already a wide variety of libraries out there, particularly in .NET 3.0/3.5, that do very well. (As you're moving to C#, I'm guessing you're already thinking along these lines :)
So ultimately, you'd have to base your decision on cost-to-implement: if you lower your cost of implementation by moving to XML or similar, make sure that you don't raise other people's cost of implementation to move to your new application framework.
Good luck!
XmlDocument - you can generate a class definition using XSD.exe