Introduction
Isolated Storage Namespace that is included in .NET Class Library is a good feature introduced in Visual Studio 2003 or later to hide certain data from the outside. The file where it actually stores those data is somewhat abstract to the user and also based on its scope specified while creating the application. In this article, I am going to discuss the basics of how to use Isolated Storage Classes and specify scope to those. The data stored through Isolated Storage is not accessible to Less trusted Applications, as they are scoped within the Assembly it produces.
The classes that we need in this project are listed below:
IsolatedStorageFile
: This is the Primary FileStream
Object. It is the main class that manages directory, files and gets store for the assembly.
IsolatedStorageFileStream
: Exposes a file within the Isolated file Location. It is the main File Stream object used for Reading or Writing on a File.
IsolatedStorageException
: It is the exception object which is thrown when any Runtime exception is generated during Isolated file Operation.
We need to include System.IO.IsolatedStorage
as well. Please note: The IsolatedStorage Classes are included in mscorlib.dll, which is automatically included. So no Reference is required.
Background
It is a very common practice to use Files to store sensitive information. Information like Web Service Path, User Settings, Application Settings are stored into Registry, config files or in some text files. The problem using them is that it does not belong to the Assembly itself, and thus should be exported whenever the assembly is exported.
Using Isolated Storage, we can include those data within the assembly itself, which will be automatically transmitted with that assembly. We may also write information to Application Data Blocks, System Files for better security. Use of Isolated Storage eliminates any Com unsecure applications to access that sensitive information.
Using the Code
This is a basic example of how we can write or fetch from an Isolated Storage. To do this, we need an object of IsolatedStorageFile
. This class has a static
function called GetStore
. We can specify what type of Store we need.
Here is the list of all scopes available :
Members Name |
Description of the Use |
None |
No Isolated Storage Usage |
User |
Isolated Storage scoped to User Identity |
Domain |
Isolated Storage Scoped to Application Domain Identity |
Assembly |
Isolated Storage Scoped to Identity of the Assembly |
Roaming |
The Isolated Storage Can roam. |
Machine |
Isolated Storage Scoped to the Machine |
Application |
Isolated Storage Scoped to the Application |
Generally we use Domain as Application Scope, which identifies the Application Domain and stores data within the Application Domain.
Now it is time to understand the code.
As far as the basics are concerned, see the code below:
using System;
using System.Windows.Forms;
using System.Text;
using System.IO;
using System.IO.IsolatedStorage;
namespace IsolatedStorage
{
public partial class ISF : Form
{
private string filename;
private string directoryname;
IsolatedStorageFile isf = null;
public ISF()
{
filename = string.Empty;
directoryname = string.Empty;
InitializeComponent();
isf = IsolatedStorageFile.GetStore(IsolatedStorageScope.User|
IsolatedStorageScope.Assembly|IsolatedStorageScope.Domain,
typeof(System.Security.Policy.Url),typeof(System.Security.Policy.Url));
}
private void button1_Click(object sender, EventArgs e)
{
LoadInfo();
}
private void LoadInfo()
{
lstDirectories.Items.Clear();
lstFileList.Items.Clear();
lstFileList.Items.AddRange(isf.GetFileNames("*"));
lstDirectories.Items.AddRange(isf.GetDirectoryNames("*"));
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
btnSave.Enabled = true;
}
private void btnSave_Click(object sender, EventArgs e)
{
try
{
IsolatedStorageFileStream isfs;
isfs = new IsolatedStorageFileStream(Path.Combine(getDirectoryName(),
getFileName()), FileMode.Create, isf);
byte[] data = Encoding.GetEncoding("utf-8").GetBytes(textBox1.Text);
isfs.Write(data, 0, data.Length);
isfs.Close();
LoadInfo();
}
catch (Exception ex)
{
MessageBox.Show("Runtime Error:" + ex.Message);
}
}
private string getDirectoryName()
{
if (directoryname == string.Empty)
{
frmNewName dialog = new frmNewName();
dialog.Text = "Enter Directory Name:";
if (dialog.ShowDialog() == DialogResult.OK)
return dialog.Path;
else
return string.Empty;
}
else
return directoryname;
}
private string getFileName()
{
if (filename == string.Empty)
{
frmNewName dialog = new frmNewName();
dialog.Text = "Enter File Name:";
if (dialog.ShowDialog() == DialogResult.OK)
return dialog.Path;
else
return string.Empty;
}
else
return filename;
}
private void lstFileList_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
filename = lstFileList.SelectedItem.ToString();
IsolatedStorageFileStream isfs = new IsolatedStorageFileStream
(Path.Combine(directoryname,filename), FileMode.Open, isf);
StreamReader sr = new StreamReader(isfs);
textBox1.Text = sr.ReadToEnd();
sr.Close();
isfs.Close();
btnSave.Enabled = false;
lblItemStat.Text = Path.Combine(directoryname, filename);
}
catch (FileNotFoundException ex)
{
MessageBox.Show("Runtime Error:" + ex.Message);
}
}
private void btnNewDir_Click(object sender, EventArgs e)
{
directoryname = string.Empty;
directoryname = getDirectoryName();
isf.CreateDirectory(directoryname);
LoadInfo();
}
private void btnFile_Click(object sender, EventArgs e)
{
filename = string.Empty;
filename = getFileName();
}
private void lstDirectories_SelectedIndexChanged(object sender, EventArgs e)
{
directoryname = lstDirectories.SelectedItem.ToString();
lstFileList.Items.Clear();
lstFileList.Items.AddRange
(isf.GetFileNames(Path.Combine(directoryname,"*")));
}
private void btnRemoveDir_Click(object sender, EventArgs e)
{
try
{
isf.DeleteDirectory(lstDirectories.SelectedItem.ToString());
directoryname = string.Empty;
LoadInfo();
}
catch (IsolatedStorageException ex)
{
MessageBox.Show("Runtime Error:" + ex.Message);
}
}
private void btnRemoveFile_Click(object sender, EventArgs e)
{
try
{
isf.DeleteFile(Path.Combine(directoryname,
lstFileList.SelectedItem.ToString()));
filename = string.Empty;
}
catch (IsolatedStorageException ex)
{
MessageBox.Show("Runtime Error:" + ex.Message);
}
}
}
}
This code might look a bit verbose to you. Ok, let us define it shortly.
To use Isolated Storage, we need to create a store for the data based on the scope we want. To get the store, we will write:
<>IsolatedStorageFile isf = IsolatedStorageFile.GetStore(IsolatedStorageScope.User|
IsolatedStorageScope.Assembly|IsolatedStorageScope.Domain, null,null);>
In the above line, I have created an object of IsolatedStorage
and got the store from Current User Domain.
After we get the Store, we need IsolatedStorageFileStream
to read or write on a particular file.
IsolatedStorageFileStream isfs = new IsolatedStorageFileStream
("abc.txt",FileMode.Create, isf);
In the above line, I have created on IsolatedStorageFileStream
, which will create "abc.txt" file if it is not existing.
After doing so, we need StreamReader
to read or StreamWriter
to write on the file.
For reading from the file, we have to use FileMode.Open
to ensure that it gives filenotfound error if the file is not found.
StreamReader sr = new StreamReader(isfs);
string fileData = sr.ReadToEnd();
StreamWriter sw = new StreamWriter(isfs);
sw.WriteLine(fileData);
If the IO operation fails, it may throw IsolatedStorageException
.
That's all we need. The others in the code are just to present you a good piece of interface.
Snapshots
In the above figure, it shows a button that invokes the Directory and Files to be loaded. The Button GetList
will list all the directory and the Files stored in the current scope.
We may change scope to get other stores too.
The save button will save the file written on the Textbox
to the chosen file. If no file is chosen yet, the file choose dialog box will be displayed.
The 3rd picture shows the dialog box that comes when the filename does not exist.
Try running the application and check. There may be some bugs on the application. I will fix them very soon.
Points of Interest
It's really fun to hide your important files from the user by including the feature of Isolated Storage classes. I think you all would have fun creating an application using this feature provided with .NET.
Functional Matrix
Instead of using GetStore
function, you may also use the Custom functions provided with IsolatedStorageFile
class. Here is the equivalence matrix:
IsolatedStorageFile.GetMachineStoreForApplication()
is equivalent to:
IsolatedStorageFile.GetStore(IsolatedStorageScope.Application |
IsolatedStorageScope.Machine, null, null);
IsolatedStorageFile.GetMachineStoreForAssembly()
is equivalent to:
IsolatedStorageFile.GetStore(IsolatedStorageScope.Assembly |
IsolatedStorageScope.Machine, null, null);IsolatedStorageFile.GetMachineStoreForDomain()
is equivalent to:
IsolatedStorageFile.GetStore(IsolatedStorageScope.Assembly |
IsolatedStorageScope.Domain | IsolatedStorageScope.Machine, null, null);
IsolatedStorageFile.GetUserStoreForApplication()
is equivalent to:
IsolatedStorageFile.GetStore(IsolatedStorageScope.Application |
IsolatedStorageScope.User, null);
IsolatedStorageFile.GetUserStoreForAssembly()
is equivalent to:
IsolatedStorageFile.GetStore(IsolatedStorageScope.Assembly |
IsolatedStorageScope.User, null, null);
IsolatedStorageFile.GetUserStoreForDomain()
is equivalent to:
IsolatedStorageFile.GetStore(IsolatedStorageScope.Assembly |
IsolatedStorageScope.Domain | IsolatedStorageScope.User, null, null);
You can use any of these functions to get its store.
History
This is the first version of the article. I would like to update the application later to make it more handy.
First Version: IsolatedStorage.zip - This is the first version of the Application. It may contain some bugs. I will fix them in future revisions. My intension is to give basic knowledge about the use of the system.