3

I'm to implement a new member application without the use of databases. I'm planning to create a class to define each member, with fields defining name, department etc. I wish to save a list of these members into a file (not plain text). So my question is to how to save a class object into a file ?

Thanks in advance :)

Ahmed Mohamed
  • 403
  • 2
  • 12
  • 20

3 Answers3

7

I would suggest doing JSON or XML serialization and then encrypting the contents with some algorithm. I wouldn't go with binary serialization because it's not very friendly when you need to change the assembly version.

I am using the following code together with Newtonsoft.Json (you can get it on NuGet) to accomplish this:

using System.IO;
using System.Security.Cryptography;
using System.Text;

using Newtonsoft.Json;

class SecureJsonSerializer<T>
    where T : class
{
    private readonly string filePath;

    private readonly ICryptoTransform encryptor;

    private readonly ICryptoTransform decryptor;

    private const string Password = "some password";

    private static readonly byte[] passwordBytes = Encoding.ASCII.GetBytes(Password);

    public SecureJsonSerializer(string filePath)
    {
        this.filePath = filePath;
        var rmCrypto = GetAlgorithm();
        this.encryptor = rmCrypto.CreateEncryptor();
        this.decryptor = rmCrypto.CreateDecryptor();
    }

    private static RijndaelManaged GetAlgorithm()
    {
        var algorithm = new RijndaelManaged();
        int bytesForKey = algorithm.KeySize / 8;
        int bytesForIV = algorithm.BlockSize / 8;
        algorithm.Key = key.GetBytes(bytesForKey);
        algorithm.IV = key.GetBytes(bytesForIV);
        return algorithm;
    }

    public void Save(T obj)
    {
        using (var writer = new StreamWriter(new CryptoStream(File.Create(this.filePath), this.encryptor, CryptoStreamMode.Write)))
        {
            writer.Write(JsonConvert.SerializeObject(obj));
        }
    }

    public T Load()
    {
        using (var reader = new StreamReader(new CryptoStream(File.OpenRead(this.filePath), this.decryptor, CryptoStreamMode.Read)))
        {
            return JsonConvert.DeserializeObject<T>(reader.ReadToEnd());
        }
    }
}
Martynas
  • 1,064
  • 10
  • 21
  • Isn't there any native .NET way to do it without any 3rd party addons ? I tend not to use external classes. – Ahmed Mohamed Feb 24 '13 at 20:58
  • Also I don't want a fully fledged encryption, just a reliable way to save and load data. – Ahmed Mohamed Feb 24 '13 at 20:59
  • 1
    Originally you had encryption in your question, that's why I posted this. Yes, you can use XmlSerializer. Here's an example using it: http://www.jonasjohn.de/snippets/csharp/xmlserializer-example.htm – Martynas Feb 24 '13 at 21:00
  • That is exactly what I'm looking for! Thanks a lot. :) EDIT: As for encryption, I thought it isn't worth it, but that code and JSON.NET is quite valuable nonetheless. Thanks again :) – Ahmed Mohamed Feb 24 '13 at 21:03
  • @Martynas Where does the password go? You only have declared and itialised it along with the byte-represenation. – Mc Midas Jul 26 '20 at 20:17
2

Sounds like you want the BinaryFormatter. This saves to a non-readable binary file. One of the major benefits of it over XmlSerialization (for example) is that your properties don't need to be public.

However I would personally like to dissuade you from this idea. I've been down this road myself and while its easy in the short term, in the long run there is a lot of pain on the way.
You will have massive issues with versioning. Whenever you want to update any object (say, add a new property) you'd have to convert all of the files.
Even worse if you want to do this within the same application you'll need both definitions available at the same time. This leads to absurdist class definitions such as:

// my original object
class SavedObject
{
    public string Data{get;set}
}

// needed to add a field for last edit
class SavedObject2
{
    public DateTime LastEdit{get;set;}

    public SavedObject2(SavedObject so){}
}

// need a small restructure so we can now have multiple datas
// 'data' is now obsolete
class SavedObject3
{
    public List<string> DataList{get;set;}
    public SavedObject3(SavedObject2 so){}
}

Serialising as a means of persistence is only good in two scenarios. One where you know the data will never change in definition (incredibly rare) and: Two where you are just saving the data in a primitive fashion (for example just a collection of strings that code then converts into classes).

I would seriously consider using a database. If you're disliking the administrative chores that come with most production databases then consider using Sqlite, it's small, portable and very easy to embed within an application.

Quibblesome
  • 25,225
  • 10
  • 61
  • 100
  • I really thought binary formatting would solve my problem :) Thanks for the code. As for SQLite it requires SQL Server to run doesn't it ? – Ahmed Mohamed Feb 24 '13 at 21:17
  • 1
    No SqlLite is embedded and portable. It doesn't require SqlServer at all. It saves to a local file and exists in a single .dll. That's why its great for small embedded applications. – Quibblesome Feb 24 '13 at 21:36
  • Worth trying and dabbling in to. Thanks a lot :) – Ahmed Mohamed Feb 25 '13 at 01:09
0

Well first you could serialize your class to json using this tool: Json Net

Second find any encryption tool from your preferences, there are a lot, here is and example : Encode to 64

After that you can save your file:

    System.File.WriteAllText(@"C:\file.dat","encripted string");
Camilo Aguilar
  • 129
  • 1
  • 11