Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

31 Days of Mango | Day #16: Isolated Storage Explorer

DZone's Guide to

31 Days of Mango | Day #16: Isolated Storage Explorer

· Mobile Zone
Free Resource

Discover how to focus on operators for Reactive Programming and how they are essential to react to data in your application.  Brought to you in partnership with Wakanda

This article is Day #16 in a series called 31 Days of Mango, and was written by guest author Samidip Basu.  Samidip can be reached on Twitter at @samidip.

Day16-IsolatedStorageExplorer

Windows Phone SDK 7.1 includes a new utility for Windows Phone Developers, called the Isolated Storage Explorer. In this article, we shall begin with the basics of Isolated Storage usage & see how the new Isolated Storage Explorer could become handy in testing applications that use Isolated Storage for files & directories, targeting both Windows Phone OS 7.0 & Windows Phone OS 7.1 runtimes.

The Basics

For Windows Phone applications, Isolated Storage is the solution to create & maintain sandboxed local storage, for any kind of persistence of data (Jeff covered this in Day #15 of the original 31 Days of Windows Phone). Abstraction of access to the underlying OS file system has the obvious advantage of security & reliability as we run third-party applications. Since our applications perform all their storage I/O against the Isolated Storage, making sure we are keeping it lean & accurate is important; this is where the Isolated Storage Explorer helps.

Isolated Storage usage can be of three types:

  • Persist Name-Value pairs through IsolatedStorageSettings class.
  • Persist Directories/Folders & Files in Isolated Storage.
  • Use SQL CE on top of Isolated Storage to persist relational data.

Of these, storing generic files & folders within Isolated Storage is pretty common usage. The Windows Phone emulator being a VM, it was tricky to test the accuracy of our Directory/File systems prior to the latest Windows Phone Mango SDK 7.1.

Now, with the SDK install, we get the Isolated Storage Explorer utility that helps us see inside/manipulate directories/files stored inside of the Isolated Storage to check for accuracy, both with the Windows Phone emulator & developer-unlocked devices. The command-line tool allows for listing files at the Root of the application’s Isolated Storage, as well as, within Directories/Sub-Directories as created by the application runtime. In addition, we can transfer entire Root/Directory of files out of the emulator/device’s Isolated Storage onto a designated folder in our computer & replace the files/directories after checks/edits back into Isolated Storage. This has distinct advantage of being able to check the file structure of our application’s storage exactly as it is inside the Isolated Storage. Also, as we manipulate file contents & directories outside the Isolated Storage & replace them back in, we get an opportunity to test how our application might respond to changes in storage structures & other edge cases. All talk so far .. shall we see some of this in action?

Our Sample Application

Let us begin with a demo Windows Phone app that creates a few sample files at the Root of Isolated Storage, as well as a few Directories with files in them. So, File > New & we begin with the Pivot template, with first section showing editable files at Root, second showing Directories with files in them & the third is a little tease Smile

File-New

As the application launches afresh, we want to hit a one-time method to set up the sample files & directories for us, starting at the Root of the application’s sandboxed Isolated Storage. So, here’s what we have in the App.xaml.cs global initialization file to set our one-time flag:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;

namespace Day16_IsolatedStorageExplorer
{
    public partial class App : Application
    {
        public PhoneApplicationFrame RootFrame { get; private set; }
        public bool FirstLaunch;

        // Constructor
        public App()
        {
            // All the automatically-added code...

            // Set the flag for fresh App launches.
            this.FirstLaunch = true;
        }

        // Everything else ...
    }
}

Now, our starting application page has a Pivot template to display the files & directories in Isolated Storage; however, as we run our application for the first time, there will be no contents in the Isolated Storage. So, here’s how we start in the code-behind to add our one-time sample files & directories; this is completely optional though if you already have content in the Isolated Storage through other means. Notice the use of Isolated Storage namespace to have access to IsolatedStorageFile & IsolatedStorageFileStream classes, which helps us in writing files to the Root of Isolated Storage or to self-created Directories:

using System;
using System.IO;
using System.IO.IsolatedStorage;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

namespace Day16_IsolatedStorageExplorer
{
    public partial class MainPage : PhoneApplicationPage
    {
        IsolatedStorageFile fileStorage;

        // Constructor
        public MainPage()
        {
            InitializeComponent();

            // Create a reference to the App's Isolated Storage
            fileStorage = IsolatedStorageFile.GetUserStoreForApplication();

            // Create initial sample Files & Directories, for fresh App Launch only.
            if ((App.Current as Day16_IsolatedStorageExplorer.App).FirstLaunch)
                this.CreateInitialFilesAndDirectories();

            // Reset the flag.
            (App.Current as Day16_IsolatedStorageExplorer.App).FirstLaunch = false;
        }

        private void CreateInitialFilesAndDirectories()
        {
            // Create a new StreamWriter, to write files to the root directory.
            StreamWriter fileWriter = new StreamWriter(new IsolatedStorageFileStream("RootFile1.txt", FileMode.OpenOrCreate, fileStorage));

            // Write sample data.
            fileWriter.WriteLine("This is test data.");

            // Close the StreamWriter.
            fileWriter.Close();

            // Repeat.
            fileWriter = new StreamWriter(new IsolatedStorageFileStream("RootFile2.txt", FileMode.OpenOrCreate, fileStorage));
            fileWriter.WriteLine("This is test data.");
            fileWriter.Close();

            // Create 2 new SubDirectories.
            fileStorage.CreateDirectory("SubDirectory1");
            fileStorage.CreateDirectory("SubDirectory2");

            // Put sample files in them.
            fileWriter = new StreamWriter(new IsolatedStorageFileStream("SubDirectory1\\SubDir1File1.txt", FileMode.OpenOrCreate, fileStorage));
            fileWriter.WriteLine("This is test data.");
            fileWriter.Close();
            fileWriter = new StreamWriter(new IsolatedStorageFileStream("SubDirectory1\\SubDir1File2.txt", FileMode.OpenOrCreate, fileStorage));
            fileWriter.WriteLine("This is test data.");
            fileWriter.Close();
            fileWriter = new StreamWriter(new IsolatedStorageFileStream("SubDirectory2\\SubDir2File2.txt", FileMode.OpenOrCreate, fileStorage));
            fileWriter.WriteLine("This is test data.");
            fileWriter.Close();
        }
    }
}

For more details & the variety of file system operations you can do with the IsolatedStorageFile & IsolatedStorageFileStream classes, please head over to the MSDN documentation here & here.

So, now we have some sample files at the Root of the Isolated Storage, as well as, in some custom Directories. Let’s see how we can scan the Isolated Storage & bring out these details in the UI. This dynamic scanning of the Isolated Storage is also going to help us test any changes made to the Isolated Storage from outside using the Isolated Storage Explorer tool. For the sake of this article’s length, the XAML markup is being skipped here; but available in the downloadable code. The only things we are adding here are a custom class called DirectorySystem to keep track of directory structures & help in binding, the code to scan for files & directories, and the bindings to the two listboxes in the Pivot controls called RootListBox & DirectorySystemListBox. So, here’s our modified code-behind for the main page:

using System;
using System.IO;
using System.IO.IsolatedStorage;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

namespace Day16_IsolatedStorageExplorer
{
    public partial class MainPage : PhoneApplicationPage
    {
        IsolatedStorageFile fileStorage;
        string[] rootFiles;
        string[] directories;
        string[] directoryFiles;

        List<DirectorySystem> listDirectorySystem = new List<DirectorySystem>();

        // Constructor
        public MainPage()
        {
            InitializeComponent();

            // Create a reference to the App's Isolated Storage
            fileStorage = IsolatedStorageFile.GetUserStoreForApplication();

            // Create initial sample Files & Directories, for fresh App Launch only.
            if ((App.Current as Day16_IsolatedStorageExplorer.App).FirstLaunch)
                this.CreateInitialFilesAndDirectories();

            // Reset the flag.
            (App.Current as Day16_IsolatedStorageExplorer.App).FirstLaunch = false;

            // Read root files.
            rootFiles = fileStorage.GetFileNames();
            this.RootListBox.ItemsSource = rootFiles;

            // Read Directories & build File system.
            directories = fileStorage.GetDirectoryNames();

            foreach (string dir in directories)
            {
                directoryFiles = fileStorage.GetFileNames(dir + "\\*");

                DirectorySystem newDir = new DirectorySystem();
                newDir.DirectoryName = dir;
                newDir.DirectoryFiles = directoryFiles;

                listDirectorySystem.Add(newDir);
            }

            // Bind to UI.
            this.DirectorySystemListBox.ItemsSource = listDirectorySystem;
        }       

        private void CreateInitialFilesAndDirectories()
        {
            // Create a new StreamWriter, to write files to the root directory.
            StreamWriter fileWriter = new StreamWriter(new IsolatedStorageFileStream("RootFile1.txt", FileMode.OpenOrCreate, fileStorage));

            // Write sample data.
            fileWriter.WriteLine("This is test data.");

            // Close the StreamWriter.
            fileWriter.Close();

            // Repeat.
            fileWriter = new StreamWriter(new IsolatedStorageFileStream("RootFile2.txt", FileMode.OpenOrCreate, fileStorage));
            fileWriter.WriteLine("This is test data.");
            fileWriter.Close();

            // Create 2 new SubDirectories.
            fileStorage.CreateDirectory("SubDirectory1");
            fileStorage.CreateDirectory("SubDirectory2");

            // Put sample files in them.
            fileWriter = new StreamWriter(new IsolatedStorageFileStream("SubDirectory1\\SubDir1File1.txt", FileMode.OpenOrCreate, fileStorage));
            fileWriter.WriteLine("This is test data.");
            fileWriter.Close();
            fileWriter = new StreamWriter(new IsolatedStorageFileStream("SubDirectory1\\SubDir1File2.txt", FileMode.OpenOrCreate, fileStorage));
            fileWriter.WriteLine("This is test data.");
            fileWriter.Close();
            fileWriter = new StreamWriter(new IsolatedStorageFileStream("SubDirectory2\\SubDir2File2.txt", FileMode.OpenOrCreate, fileStorage));
            fileWriter.WriteLine("This is test data.");
            fileWriter.Close();
        }
    }

    public class DirectorySystem
    {
        public string DirectoryName { get; set; }
        public string[] DirectoryFiles { get; set; }
    }
}

Seems like a lot of code? Want to try this yourself? The easiest way to make sense of the code is to download the source code solution through the link at the end of the article & run the application yourself. As we deploy our application fresh to the emulator, the above one-time method kicks in creating the sample files at the Root & designated custom Directories. Next, we have code to scan the Isolated Storage for file & directories and bind to UI. If all is well, you can just hit F5 to run the application, which should look like this:

Demo AppDirectories with FilesRoot Files

Now, we can see the files in Isolated Storage. Wouldn’t it be nice if we could open up each individual file to look into its contents & also be able to do edits on them? So, let’s do it! This way, our Isolated Storage Explorer will be able to check for file content after edits & we shall also be able to test how our application behaves when given random file edits at its Root from outside the emulator. This can definitely be done for files inside a Directory; but you get the point. Now, to pull this off, we’re going to add a simple second XAML page to our project and allow it to open up individual files for content editing. Here’s the simple intended UI:

Root File Edits

Let’s see how we got here. First, we assign a MouseLeftButtonUp event handler to the RootListBox in the main pivot page, so we can identify which file the user tapped on. Next, we add this snippet as an event handler in the code-behind:

private void RootListBox_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    if (this.RootListBox.SelectedItem != null)
    {
        string selectedFileName = this.RootListBox.SelectedItem.ToString();
        this.NavigationService.Navigate(new Uri("/FileContent.xaml?FileName=" + selectedFileName, UriKind.Relative));

        this.RootListBox.SelectedItem = null;
    }
}

So, essentially all we are doing here is carrying the File name of the selected file on to our second XAML page. Now, let’s see how we read the File in our new page, open it up for edits & finally save the changes the user might make:

using System;
using System.IO;
using System.IO.IsolatedStorage;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

namespace Day16_IsolatedStorageExplorer
{
    public partial class FileContent : PhoneApplicationPage
    {
        string currentFileName;

        private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
        {
            if (this.NavigationContext.QueryString.ContainsKey("FileName"))
            {
                currentFileName = this.NavigationContext.QueryString["FileName"];
                this.actualFileName.Text = currentFileName;

                this.ReadFileData(currentFileName);
            }
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            this.EditFileData(currentFileName);
        }

        private void ReadFileData(string filePath)
        {
            using (IsolatedStorageFile appIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (appIsolatedStorage.FileExists(filePath))
                {
                    using (IsolatedStorageFileStream fileStream = appIsolatedStorage.OpenFile(filePath, FileMode.Open, FileAccess.Read))
                    {
                        using (StreamReader reader = new StreamReader(fileStream))
                        {
                            this.fileContent.Text = reader.ReadLine();
                        }
                    }
                }
            }
        }

        private void EditFileData(string filePath)
        {
            using (IsolatedStorageFile appIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (appIsolatedStorage.FileExists(filePath))
                {
                    using (IsolatedStorageFileStream fileStream = appIsolatedStorage.OpenFile(filePath, FileMode.Open, FileAccess.Write))
                    {
                        using (StreamWriter writer = new StreamWriter(fileStream))
                        {
                            string editedText = this.fileContent.Text.Trim();
                            writer.Write(editedText);
                            writer.Close();
                        }
                    }
                }
            }

            this.NavigationService.Navigate(new Uri("/DirectoryListings.xaml", UriKind.Relative));
        }

    }
}

 

Notice how as the page loads up, we read the File name from the query parameter, as was passed in from our Pivot page. Equipped with just the File name & a reference to the application’s own Isolated Storage, the ReadFileData method is able to locate the file and open it read mode for display. What happens when the user makes some edits to the file content & hits the Save button? No worries! We simply call into the EditFileData method which locates & opens the file, this time in Write mode & uses an IsolatedStorageFileStream object to write the updated content back into the file. Voila!

You’ll notice that so far we have been able to create & edit sample files into Isolated Storage, as well as, manage custom Directories. While all this is encouraging, would you not get more confidence if you could actually see the file structure inside the emulator/device to check on the files/directories & their content? Doubt no longer, as the Isolated Storage Explorer is here to help.

Isolated Storage Explorer Usage

The Isolated Storage Explorer is a command-line tool that comes bundled with Windows Phone SDK 7.1. The utility comes as ISETool.exe and can be found in the appropriate Program Files\MSFT SDKs\Windows Phone\v7.1\Tools\IsolatedStorageExplorerTool directory. So, let’s fire up our command prompts & navigate to the above directory so we can invoke the command-line tool.

Let’s get started. The ISE Tool can look inside the Isolated Storage of the emulator or a developer-unlocked device. The application who’s Isolated Storage you want to look into needs to installed on the running emulator or device, but the app does not need to be running since Isolated Storage is persisted. Just like any other command-line tool, the ISE Tool comes with some syntactical options to carry out various commands. The general syntax is the following; we shall look into each of the options separately:

ISETool.exe <ts|rs|dir[:device-folder]> <xd|de> <Product GUID> [<computer-path>]

With our demo Windows Phone application, we had created a one-time sample of files & custom directories. Let’s say our app isn’t running and we just wanted to take a peek inside the sandboxed Isolated Storage. Here’s the command:

ISETool.exe dir xd 04ce6350-faf0-4977-8e5b-fb288fc127c0

The breakdown is as follows:

  • ISETool.exe = Command-line tool.
  • dir = Lists out the files and directories from a specified Isolated Storage directory or the root if nothing is specified.
  • xd = This indicates that we are looking into the Isolated Storage of the emulator.
  • de = This would turn the same command to look into the Isolated Storage of an attached Windows Phone device.
  • <Product GUID> = This is the specific Application ID so that the tool knows which sandboxed environment it’s looking into. The Product GUID can be found in the WMAppManifest.xml file for each Windows Phone application.

That’s it. Our command-line friend lists out the sample files in the Root Isolated Storage directory as well as the custom SubDirectories created. Want to take a peek inside one of our custom Directories in Isolated Storage? Here’s the command:

ISETool.exe dir:"SubDirectory1" xd 04ce6350-faf0-4977-8e5b-fb288fc127c0

You’ll notice that everything remains the same as the last command; but instead of looking at the Root of the Isolated Storage, the tool now lists out all Files/Sub-Directories within the specified Directory.

Now, the really fun part! What if you wanted to rip out the entire Isolated Storage container for a Windows Phone application out of the emulator or device? Well, sure you can .. here’s how:

ISETool.exe ts xd 04ce6350-faf0-4977-8e5b-fb288fc127c0 "C:\Users\Sami\Desktop"

Two things were new here:

  • ts = Take Snapshot. As the name suggests, this takes a full snapshot of the Root files/Directory structure as specified.
  • <Computer Path> = This simply tells the Isolated Storage Explorer to copy emulator/device Isolated Storage on to the specified local machine folder.

This copies over all contents from the Root of the specified Isolated Storage onto a folder called “IsolatedStore” in the specified computer/desktop path; this folder & its contents will be overwritten if they pre-exist. The same command can copy out only the contents of a SubDirectory from Isolated Storage, if a path is specified. If your application is targeting the Windows Phone 7.1 runtime, the copied out “IsolatedStore” directory will have a folder called “Shared” – this houses the application-specific Background Transfer data & ShellContent for secondary Live Tiles. Here’s how it could look if copied to desktop:

Transfers-out-of-Emulator[1]

Now, how about replacing files/directories back from your computer into Isolated Storage? This is great for testing, as it allows you to inspect how your application handles changes in file content, as well as Directory structure changes. Here’s the command:

ISETool.exe rs xd 04ce6350-faf0-4977-8e5b-fb288fc127c0 "C:\Users\Sami\Desktop\IsolatedStore"

What’s new?

  • rs = Restore Snapshot. As the name suggests, this replaces the files & directories in Isolated Storage on the emulator/device with corresponding directory contents from your computer. Notice that to put back the changed contents from what we pulled out from the Isolated Storage, we had to add the “IsolatedStore” to our computer source path.

Watch us add a random text file to the “IsolatedStore”, which corresponds to the root of the Isolated Storage:

File Additions

After running the command through the Isolated Storage Explorer, the file magically (ok, not really) shows up in the concerned Isolated Storage. And sure enough, our Windows Phone application picks up the changes in directory structure, along with the correct file content on the next run:

File Transfer into EmulatorFile Contents from Desktop

And you can see the output of all the commands we ran so far, just so you know exactly what to expect:

ISE Command Runs

Summary

That’s it! Now, no matter what files/folders you are storing in Isolated Storage for your Windows Phone applications, you can now use the Isolated Storage Explorer to be totally confident in the directory structure & file contents of your persistent storage. Let’s go build some Windows Phone applications now, shall we?

Adios!

To download an entire working Windows Phone application that you can use with the Isolated Storage Explorer, click on the Download Code button below:

download[1]

Tomorrow, we we look at another Isolated Storage topic, using a Local Database in your application.  See you then!

toolsbutton[1]


Source: http://www.jeffblankenburg.com/2011/11/16/31-days-of-mango-day-16-isolated-storage-explorer

Learn how divergent branches can appear in your repository and how to better understand why they are called “branches".  Brought to you in partnership with Wakanda

Topics:

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}