C# Tutorials and offshore development in India
    Tutorials   Resources   Forum   Interview   Jobs   Projects   Offshore Development    
Mentor | Code Converter | Articles | Code Factory | Computer Jokes | Members | Peer Appraisal | IT Companies | Bookmarks | Revenue Sharing | Talk to Us |



My Profile

Gifts

Active Members
TodayLast 7 Days more...







Persisting Application data using Hashtable and IsolatedStorage


Posted Date: 13 Apr 2004    Resource Type: Articles    Category: .NET Framework

Posted By: Tony John       Member Level: Gold
Rating:     Points: 10



Download sample Application



Introduction

The .NET Framework provides the concept of 'application configuration file' to store application settings. The config file is a regular XML file and need to be shipped with the application. Since this is a simple XML file, users can make changes to the configuration data using any simple text editor, without the need to recompile the application.

Limitations of Application Configuration File

Config files are very handy and easy to use. But there are few limitations:

1. This is a read only mechanism. You cannot use the .NET ConfigurationSettings class to update the app.config file. Since the config file is a simple XML file, you can write your own class to update the data from your application. But in Windows environment, until you restart the application, the changes to the config file will not be recognized by the application. In web applications, if you update the web.config, the ASP.NET worker thread will be recycled.

2. Security Threat - The config file is accessible to everyone who has access to the File system. It is possible that user may edit the config file manually and mess up with the content or provide invalid settings.

Alternate approaches

1. Registry
2. File
3. Isolated Storage
4. Serialize Custom classes

Each of the above approached have advantages and disadvantages.

Writing into registry may need more permissions than otherwise required by the application. Also, it is possible that any other application can accidentaly or deliberately overwrite the registry data. Writing into File also requires specific permissions. Also, the question of where to store the file, how to secure it etc raises.

What is Isolated Storage ?

.NET introduces a concept called Isolated Storage. Isolated Storage is a kind of Virtual Folder.
Users never need to know where exactly the file is stored. All you do is, telling the .net framework to store your file in Isolated Storage. The physical location of Isolated Storage varies for each Operating System. But your application simply uses the .net classes to create and access files, without bothering where it is physically located. And you can have Isolated Storage specific to each Assembly or each WIndows user. Since Isolated Storage can be specific to each user or assembly, you don't need to worry about other users accidentally changing your files.

Persisting Application Data - Overview

In this article, I will demonstrate a custom class that can be used to easily store and retrieve application data. This custom class uses various features including Hashtable, serialization and isolated storage to manipulate and store application data. The application data is stored in a hashtable as Key-Value pairs. Hashtable supports inserting any kind of objects into it. So this class, which is derived from Hashtable, will support saving any objects into the persistent storage. When the Save() method is called, the hashtable data will be serialized into Isolated Storage. In the constructor of the class, it will load data by deserializing itself from the data stored in Isolated Storage.

Concepts

I have written a custom class to store and retrieve custom application data in an easy and reliable manner, combining the above approaches. My approach makes use of the following .NET Framework concepts:

1. Hashtable - used to store data as key value pairs.
2. Serialization - to persists the hashtable into the file system.
3. Isolated Storage - to protect data from other users and assemblies.

Code Sample

using System;
using System.Collections;
using System.IO;
using System.IO.IsolatedStorage;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace CustomStorage
{
[Serializable]
public class ApplicationStorage : Hashtable
{
// File name. Let us use the entry assembly name with .dat as the extension.
private string settingsFileName =
System.Reflection.Assembly.GetEntryAssembly().GetName().Name + ".dat";

// The default constructor.
public ApplicationStorage()
{
LoadData();
}

// This constructor is required for deserializing our class from persistent storage.
protected ApplicationStorage (SerializationInfo info, StreamingContext context)
: base(info, context)
{
}

private void LoadData()
{
IsolatedStorageFile isoStore = IsolatedStorageFile.GetStore( IsolatedStorageScope.User
| IsolatedStorageScope.Assembly, null, null );
if ( isoStore.GetFileNames( settingsFileName ).Length == 0 )
{
// File not exists. Let us NOT try to DeSerialize it.
return;
}

// Read the stream from Isolated Storage.
Stream stream = new IsolatedStorageFileStream( settingsFileName,
FileMode.OpenOrCreate, isoStore );
if ( stream != null )
{
try
{
// DeSerialize the Hashtable from stream.
IFormatter formatter = new BinaryFormatter();
Hashtable appData = ( Hashtable ) formatter.Deserialize(stream);

// Enumerate through the collection and load our base Hashtable.
IDictionaryEnumerator enumerator = appData.GetEnumerator();
while ( enumerator.MoveNext() )
{
this[enumerator.Key] = enumerator.Value;
}
}
finally
{
// We are done with it.
stream.Close();
}
}
}

public void ReLoad()
{
LoadData();
}

// Saves the configuration data to the persistent storage.
public void Save()
{
// Open the stream from the IsolatedStorage.
IsolatedStorageFile isoStore = IsolatedStorageFile.GetStore( IsolatedStorageScope.User
| IsolatedStorageScope.Assembly, null, null );
Stream stream = new IsolatedStorageFileStream( settingsFileName,
FileMode.Create, isoStore );

if ( stream != null )
{
try
{
// Serialize the Hashtable into the IsolatedStorage.
IFormatter formatter = new BinaryFormatter();
formatter.Serialize( stream, (Hashtable)this );
}
finally
{
stream.Close();
}
}
}
}
}


Let us analyze the code now.

public class ApplicationStorage : Hashtable


The class definition shows that it inherits the Hashtable. So, you can use all features of a Hashtable. This will help Add and Remove key value pairs easily. Also, the hashtable provides a very efficient mechanism to handle objects.

Constructor:

public ApplicationStorage()
{
LoadData();

}


Inside the constructor, we will call the LoadData() method. When this class is instantiated, it will load the previously stored data into it's Hashtable. let us see the implementation of the method LoadData()

private void LoadData()
{
IsolatedStorageFile isoStore = IsolatedStorageFile.GetStore( IsolatedStorageScope.User
| IsolatedStorageScope.Assembly, null, null );
if ( isoStore.GetFileNames( settingsFileName ).Length == 0 )
{
// File not exists. Let us NOT try to DeSerialize it.
return;
}

// Read the stream from Isolated Storage.
Stream stream = new IsolatedStorageFileStream( settingsFileName,
FileMode.OpenOrCreate, isoStore );
if ( stream != null )
{
try
{
// DeSerialize the Hashtable from stream.
IFormatter formatter = new BinaryFormatter();
Hashtable appData = ( Hashtable ) formatter.Deserialize(stream);

// Enumerate through the collection and load our base Hashtable.
IDictionaryEnumerator enumerator = appData.GetEnumerator();
while ( enumerator.MoveNext() )
{
this[enumerator.Key] = enumerator.Value;
}
}
finally
{
// We are done with it.
stream.Close();
}
}
}

We are using the IsolatedStorageFile class provided by the .Net Framework to get access to the 'Store'. The parameters specify that this store is specific to the 'current windows user' and also to the 'current assembly'. Next we are checking if the file we are looking for already exists in store. If it doesn't exists, we do not process it.

In the next few steps, we will read data from the stream and Deserialize a Hashtable. After Deserializing the Hashtable, we will enumerate through the entries and assign to the base class Hashtable.

In short, we are loading the hashtable by deserializing the previously serialized hashtable data in isolated storage.

Next, let us see the Save() method. As the name indicates, it saves the data in Hashtable into the isolated Storage.

public void Save()
{
// Open the stream from the IsolatedStorage.
IsolatedStorageFile isoStore = IsolatedStorageFile.GetStore( IsolatedStorageScope.User
| IsolatedStorageScope.Assembly, null, null );
Stream stream = new IsolatedStorageFileStream( settingsFileName,
FileMode.Create, isoStore );

if ( stream != null )
{
try
{
// Serialize the Hashtable into the IsolatedStorage.
IFormatter formatter = new BinaryFormatter();
formatter.Serialize( stream, (Hashtable)this );
}
finally
{
stream.Close();
}
}
}


In the first step, we are opening the 'Store' in IsolatedStorage. The parameters specify that this store is specific to the 'current windows user' and also to the 'current assembly'. Next we create a file in this store. The parameter 'FileMode.Create' will ensure that the file will be created if it doesn't exist.

In the next step, we will deserialize the hashtable entries into the stream. This will save all our data in the hashtable into the Isolated Storage, which can be later deserialized in the LoadData() method.

Let us see some sample code to consume this little handy tool.

CustomStorage.ApplicationStorage storage = new CustomStorage.ApplicationStorage();

storage["name"] = "john";

storage["age"] = 23;

storage["address"] = "#10, Vasant Nagar";

storage.Save();


In the above sample code, we are creating an instance of our class ApplicationStorage and adding key/value pairs to it. Since our class inherits the Hashtable, we can use all methods of Hashtable including Add(...), indexer (this), Remove(), Clear() etc. The Save() method will serialize the data into Isolated Storage.

Since Hashtable supports any objects, you can use this class to store any kind of serializable objects.

The following sample code demonstrates how you can retrieve data.

CustomStorage.ApplicationStorage storage = new CustomStorage.ApplicationStorage();

string name = storage["name"].ToString();

int age = int.parse(storage["age"].ToString());

string address = storage["address"].ToString();


When the class is instantiated, it will load the already saved data. Then you can use the indexer property of the Hashtable to retrieve all key/Value pairs from it.

Disadvantages

Our class uses Isolated Storage and it has few limitations. First thing is, Administrator can set quota per user and per assembly. This will be a limitation and our utility will fail if it exceeds the limit. Also, smart users can find the location of Isolated Storage. Even though it is a hidden location, it is possible that someone can locate it and remove or corrept our files. So, it doesn't
give very high security for data.

Download sample Application


Please submit your comments using the feedback form below.




Responses

Author: Yunus Ahamed    17 Jun 2004Member Level: Bronze   Points : 0
Example u gave is very good, i hope all would make use of this one.

Thanks
Ahamed


Author:     26 Jun 2004Member Level: Bronze   Points : 0
The article is good. Please do tell in which folder the Information is saved. How is the folder mapped into the physical location.

Thanks
Anil


Author: Fernando    26 Oct 2004Member Level: Bronze   Points : 0
good article. clear and usefull. One question thought: is it possible to change the limits in the quota per user and per assembly? If so how?
thanks


Author: Ralf Klatt    17 Nov 2004Member Level: Bronze   Points : 0
Hi,
... what a great chance ... this afternoon i've received a lesson to do at a private academy ... and looking at Google I've found this solution!
To tell you ... we're still the beginners and we're still working at the Console-Level ... but anyway ... the provided solution is easyly adaptable to a Console-Solution too! ... I'm glad to have found this sample and I hope I'll find a way to share my Console-Solution with this community ...
Thanks a lot from Germany!!!


Author: Manish Jain    28 Feb 2005Member Level: Bronze   Points : 0
This article is good but I want to modify value of the web.config file dynamically by the application which is using that configuration file. Is it possible to do same i am using the following code to achive the same and it is throwing an error of access denied:
CodeBehind:-

XmlDocument xdConfig = new XmlDocument();
XmlNode xnAdd = null;
xdConfig.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
xnAdd = xdConfig.SelectSingleNode("//configuration/customSystemItems/add[@key='ActiveRootFolder']");
xnAdd.Attributes.GetNamedItem("value").InnerText = "Testing";
xdConfig.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);


Configuration file:-









Regards
Manish


Author: Kunal Shah    06 Apr 2005Member Level: Bronze   Points : 0
good article


Author: Jayaprakash    01 Aug 2005Member Level: Bronze   Points : 0
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(@"C:\Documents and Settings\jayaprakashd\My Documents\Visual Studio Projects\WinAppset\App.config");
XmlNode appsettingnode = xmldoc.SelectSingleNode("//configuration/appSettings");
XmlElement xmlnewelem = xmldoc.CreateElement("add");
xmlnewelem.SetAttribute("key",textBox1.Text);
xmlnewelem.SetAttribute("value",textBox2.Text);
appsettingnode.AppendChild(xmlnewelem);
xmldoc.Save(@"C:\Documents and Settings\jayaprakashd\My Documents\Visual Studio Projects\WinAppset\App.config");


Feedbacks      
Popular Tags   What are tags ?   Search Tags  
(No tags found.)

Post Feedback


This is a strictly moderated forum. Only approved messages will appear in the site. Please use 'Spell Check' in Google toolbar before you submit.
You must Sign In to post a response.
Next Resource: Retrieving the name and parameters of current method using Reflection
Previous Resource: Introduction to Constructors in C#
Return to Discussion Resource Index
Post New Resource
Category: .NET Framework


Post resources and earn money!
 
Related Resources



dotNet Slackers   BizTalk Adaptors    Web Design

doors in nj

Contact Us    Privacy Policy    Terms Of Use