[ Team LiB ] Previous Section Next Section

11.2 Programming Isolated Storage

Isolated storage is simple to use and requires knowledge of relatively few classes. The most important class is System.IO.IsolatedStorage.IsolatedStorageFile. IsolatedStorageFile objects represent individual stores and provide methods to manage the files and directories contained within the stores, as well as properties to access information, such as the store's isolation scope, current size, and maximum size. The IsolatedStorageFile class also provides static factory methods through which you initially obtain store objects.

Also important is the System.IO.IsolatedStorage.IsolatedStorageFileStream class, which extends System.IO.FileStream and provides the mechanism through which you read and write data to files in isolated storage.

In the following sections, we demonstrate how to use these classes to implement the use of isolated storage in your programs. First, we look at the code-access permissions used to control access to isolated storage.

11.2.1 Isolated Storage and Code-Access Security

The System.Security.Permissions.IsolatedStorageFilePermission code-access permission class controls access to isolated storage. Unlike the System.Security.Permissions.FileIOPermission class that controls direct access to the hard drive, the IsolatedStorageFilePermission class does not control the type of access (read or write) to specific directories or even specific stores. IsolatedStorageFilePermission controls access to isolated storage by restricting the scope of isolation at which code can obtain a store. Permission to obtain a store of a specified scope implies the ability for code to read and write data in the store. The IsolatedStorageFilePermission class also controls the maximum size that code can make a store.

If different code obtains the same store, the maximum store size granted to each assembly may be different based on the configuration of the IsolatedStorageFilePermission granted to the each assembly.

When configuring IsolatedStorageFilePermission instances, the System.Security.Permissions.IsolatedStorageContainment enumeration represents the different isolation scopes available, as well as some levels of access that transcend the individual isolation scopes. Table 11-1 lists the members of the IsolatedStorageContainment enumeration and describes the access they represent.

Table 11-1. Members of the IsolatedStorageContainment enumeration

Member

Description

None

No permission to access isolated storage

DomainIsolationByUser

Permission to obtain a nonroaming store isolated by user, assembly, and application domain

AssemblyIsolationByUser

Permission to obtain a nonroaming store isolated by user and assembly

DomainIsolationByRoamingUser

Permission to obtain a roaming store isolated by user, assembly, and application domain

AssemblyIsolationByRoamingUser

Permission to obtain a roaming store isolated by user and assembly

AdministerIsolatedStorageByUser

Permission to enumerate and obtain all stores for the current user, but not the ability to modify the stores contents

UnrestrictedIsolatedStorage

Grants code unrestricted access to all stores isolated by the current user

The IsolatedStorageFilePermission treats the DomainIsolationByUser, AssemblyIsolationByUser, DomainIsolationByRoamingUser, and AssemblyIsolationByRoamingUser values of the IsolatedStorageContainment enumeration as a hierarchy of permissions. This introduces an important inconsistency in the control of access to isolated storage. Granting code the DomainIsolationByRoamingUser permission results in the code also obtaining a store isolated by user and assembly (AssemblyIsolationByUser) only. This introduces a significant risk because an assembly used by multiple applications can leak data between those applications, when the expected behavior allows code to obtain a roaming store isolated by user, assembly, and application domain.

Despite the relative safety of isolated storage, .NET's default security policy (discussed in Chapter 9) restricts the isolation scope of stores some code can obtain. In particular, code run from the Internet can obtain only a store isolated by user, assembly, and application domain. This minimizes the chance that applications downloaded from the Internet can share data between each other.

If you intend to use isolated storage in your code, it is prudent to use a permission request, which we discussed in Chapter 7, to ensure the runtime grants your code the isolation scope it requires. The following code demonstrates the statements that request permission to create stores of some sample isolation scopes:

# C#

// Minimum permission request to obtain a non-roaming store isolated by 
// user, assembly, and application domain
[assembly:IsolatedStorageFilePermission(SecurityAction.RequestMinimum,
UsageAllowed = IsolatedStorageContainment.DomainIsolationByUser)]

// Minimum permission request to obtain a roaming store isolated by 
// user and assembly with a quota of 2048 bytes
[assembly:IsolatedStorageFilePermission(SecurityAction.RequestMinimum,
UsageAllowed = IsolatedStorageContainment.AssemblyIsolationByRoamingUser,
UserQuota = 2048)]

// Minimum permission request for unrestricted access to isolated storage
[assembly:IsolatedStorageFilePermission(SecurityAction.RequestMinimum,
Unrestricted = true)]

# Visual Basic .NET

' Minimum permission request to obtain a non-roaming store isolated by 
' user, assembly, and application domain
<Assembly:IsolatedStorageFilePermission(SecurityAction.RequestMinimum, _
UsageAllowed := IsolatedStorageContainment.DomainIsolationByUser)>

' Minimum permission request to obtain a roaming store isolated by 
' user and assembly with a quota of 2048 bytes
<Assembly:IsolatedStorageFilePermission(SecurityAction.RequestMinimum, _
UsageAllowed:=IsolatedStorageContainment.AssemblyIsolationByRoamingUser, _
UserQuota := 2048)>

' Minimum permission request for unrestricted access to isolated storage
<Assembly:IsolatedStorageFilePermission(SecurityAction.RequestMinimum, _
Unrestricted := true)>

You cannot Assert the IsolatedStorageFilePermission in your code; attempts to Assert are ignored.

11.2.2 Obtaining a Store

Two static methods of the IsolatedStorageFile class provide the simplest and most common way of obtaining a store:

GetUserStoreForAssembly

Returns a nonroaming store isolated by user and assembly. To invoke GetUserStoreForAssembly, the calling code must have the AssemblyIsolationByUser element of the IsolatedStorageFilePermission permission.

GetUserStoreForDomain

Returns a nonroaming store isolated by user, assembly, and application domain. To invoke GetUserStoreForDomain, the calling code must have the DomainIsolationByUser element of the IsolatedStorageFilePermission permission.

Both methods take no arguments and return an IsolatedStorageFile object representing the store with the appropriate identity for the current user and code. If a store with the necessary identity does not already exist, isolated storage creates a new one. The following statements demonstrate the use of both methods:

# C#

// Obtain a store isolated by user and assembly
IsolateStorageFile iso1 = IsolatedStorageFile.GetUserStoreForAssembly(  );

// Obtain a store isolated by user, assembly, and application domain
IsolateStorageFile iso2 = IsolatedStorageFile.GetUserStoreForDomain(  );

# Visual Basic .NET

' Obtain a store isolated by user and assembly
Dim iso1 As IsolateStorageFile =_
IsolatedStorageFile.GetUserStoreForAssembly(  ) 
 
' Obtain a store isolated by user, assembly, and application domain
Dim iso2 As IsolateStorageFile = _
IsolatedStorageFile.GetUserStoreForDomain(  )

The static IsolatedStorageFile.GetStore method also obtains a store, but allows the caller to specify the scope and identity of the store to obtain. GetStore has three overloads that provide different ways to specify the identity of the store. We show the most commonly used signature here; refer to the .NET Framework documentation for a discussion of all available overloads:

# C#

public static IsolatedStorageFile GetStore {
    IsolatedStorageScope scope,
    object domainIdentity,
    object assemblyIdentity
);

# Visual Basic .NET

Overloads Public Shared Function GetStore( _
    ByVal scope As IsolatedStorageScope, _
    ByVal domainIdentity As Object, _
    ByVal assemblyIdentity As Object _
) As IsolatedStorageFile

The domainIdentity and assemblyIdentity arguments represent the evidence objects for isolated storage to use when determining the identity of the store to obtain. Specifying null (C#) or Nothing (Visual Basic .NET) for both arguments means isolated storage will use its default approach to determine code identity, which we discussed earlier in Section 11.1.1.1.

The scope argument takes a value of the System.IO.IsolatedStorage.IsolatedStorageScope enumeration that identifies the desired isolation scope for the store. The IsolatedStorageScope enumeration contains the following five values:

  • Assembly

  • Domain

  • None

  • Roaming

  • User

By themselves, these values serve no purpose; only by combining them using a logical Or operation do they have any meaning to the GetStore method. Table 11-2 lists the valid combination of values. The | symbol is the C# equivalent of the Visual Basic .NET Keyword Or.

Table 11-2. Valid IsolatedStorageScope values for GetStore

Values

Description

User | Assembly

Requests a store isolated by user and assembly, the same as that returned by the GetUserStoreForAssembly method

User | Assembly | Domain

Requests a store isolated by user, assembly, and application domain, the same as that returned by the GetUserStoreForDomain method

Roaming | User | Assembly

Requests a roaming store isolated by user and assembly

Roaming | User | Assembly | Domain

Requests a roaming store isolated by user, assembly, and application domain

GetStore is the only way to obtain stores backed by Windows-roaming profiles. If you use GetUserStoreForAssembly, GetUserStoreForDomain, or do not specify the Roaming flag when calling GetStore, the store will exist only on the machine on which it was created and will not be accessible to the user when she uses other machines.

Because the GetStore method allows you to override the default evidence used to identify the store to obtain, you can obtain another application's store if you specify the correct evidence values—a relatively easy task. This breaks the normal code-level isolation provided by isolated storage; therefore, the calling code must have the more highly trusted AdministerIsolatedStorageByUser element of the IsolatedStorageFilePermission to call GetStore with evidence arguments that are not null (C#) or Nothing (Visual Basic .NET).

The following statements demonstrate the use of the GetStore method, including method calls that are equivalent to calling the GetUserStoreForAssembly and GetUserStoreForDomain methods:

# C#

// GetStore equivalent of GetUserStoreForAssembly
IsolatedStorageFile iso1 = IsolatedStorageFile.GetStore(
    IsolatedStorageScope.User | IsolatedStorageScope. Assembly,
    null, null
);
        
// GetStore equivalent of GetUserStoreForDomain
IsolatedStorageFile iso2 = IsolatedStorageFile.GetStore(
    IsolatedStorageScope.User | IsolatedStorageScope.Assembly |
    IsolatedStorageScope.Domain, null, null
);

// Get a roaming store isolated by user and assembly. Specify
// new Url evidence for the assembly identity
IsolatedStorageFile iso3 = IsolatedStorageFile.GetStore(
    IsolatedStorageScope.User | IsolatedStorageScope.Assembly |
    IsolatedStorageScope.Roaming, null, new Url(@"http://test.com")
);

# Visual Basic .NET

' GetStore equivalent of GetUserStoreForAssembly
Dim iso1 As IsolatedStorageFile = IsolatedStorageFile.GetStore( _
IsolatedStorageScope.User Or IsolatedStorageScope.Assembly, _
Nothing, Nothing)
 
' GetStore equivalent of GetUserStoreForDomain
Dim iso2 As IsolatedStorageFile = IsolatedStorageFile.GetStore( _
IsolatedStorageScope.User Or IsolatedStorageScope.Assembly Or _
IsolatedStorageScope.Domain, Nothing, Nothing) 
 
' Get a roaming store isolated by user and assembly. Specify
' new Url evidence for the assembly identity
Dim iso3 As IsolatedStorageFile = IsolatedStorageFile.GetStore( _
IsolatedStorageScope.User Or IsolatedStorageScope.Assembly Or _
IsolatedStorageScope.Roaming, Nothing, New Url("http://test.com"))

The final way to obtain a store is to enumerate all stores for the current user. This breaks the data isolation provided by isolated storage completely and requires the caller to have the AdministerIsolatedStorageByUser element of the IsolatedStorageFilePermission permission. The IsolatedStorageFile.GetEnumerator method has the following signature:

# C#
public static IEnumerator GetEnumerator(
    IsolatedStorageScope scope
);

# Visual Basic .NET

Public Shared Function GetEnumerator( _
    ByVal scope As IsolatedStorageScope _
) As IEnumerator

The scope argument takes a value of the IsolatedStorageScope enumeration; Table 11-3 lists the valid member combinations.

Table 11-3. Valid IsolatedStorageScope values for GetEnumerator

Values

Description

User

Returns an enumeration across all nonroaming stores for the current user

Roaming | User

Returns an enumeration across all roaming stores for the current user

You can read data from IsolatedStorageFile objects obtained through the GetEnumerator method, but you cannot write to them. Methods that write data to stores ensure that no write operation increases the size of the store beyond that specified by the IsolatedStorageFilePermission permission granted to the executing code. When code obtains a store through the GetStore, GetUserStoreForAssembly, or GetUserStoreForDomain methods, the code's permissions determine the maximum size of the store. This figure is stored in the IsolatedStorageFile.MaximumSize property. However, code that executes GetEnumerator has no defined quota and so no maximum size is set. The lack of a maximum size value does not, however, result in an unrestricted store quote. Any attempt by code that obtains a store using GetEnumerator to read or modify the MazimumSize property will cause a System.InvalidOperationException to be thrown.

Example 11-1 demonstrates the use of the GetEnumerator method to obtain all nonroaming stores for the current user. We then step through the stores and display the stores' isolation scope, current size, and the evidence of the code that created the stores using the Scope, CurrentSize, AssemblyIdentity, and DomainIdentity properties:

Example 11-1. Enumerating and displaying the characteristics of isolated stores
# C#

using System;
using System.Collections;
using System.IO.IsolatedStorage;
using System.Security.Permissions;

// Ensure we have permission to enumerate stores
[assembly:IsolatedStorageFilePermission(SecurityAction.RequestMinimum,
UsageAllowed = IsolatedStorageContainment.AdministerIsolatedStorageByUser)]

public class EnumerateStores {

    public static void Main(  ) {
    
        // Obtain an IEnumerator across all non roaming stores for the 
        // current user
        IEnumerator e = 
            IsolatedStorageFile.GetEnumerator(IsolatedStorageScope.User);
        
        // Iterate through the enumerator
        while (e.MoveNext(  )) {
       
                IsolatedStorageFile i = (IsolatedStorageFile)e.Current;
        
                // Display the scope of the current store
                Console.WriteLine("STORE SCOPE: {0}", i.Scope);
       
                // Display the maximum and current size for the store
                Console.WriteLine("Current size={0}", i.CurrentSize);
       
                // Display the assembly identity of the current store
                Console.WriteLine("Assembly ID:");
                Console.WriteLine(i.AssemblyIdentity);
       
                // Display the domain identity of the current store if
                // the store is isolated by domain
                if ((i.Scope & IsolatedStorageScope.Domain) != 0) {
                        
                        Console.WriteLine("Domain ID:");
                        Console.WriteLine(i.DomainIdentity);
            }
        }
    }
}
       
# Visual Basic .NET

Imports System
Imports System.Collections
Imports System.IO.IsolatedStorage
Imports System.Security.Permissions
 
' Ensure we have permission to enumerate stores
<assembly:IsolatedStorageFilePermission(SecurityAction.RequestMinimum, _
UsageAllowed := IsolatedStorageContainment.AdministerIsolatedStorageByUser _
)> _ 
 
Public Class EnumerateStores
 
    Public Shared  Sub Main(  )
 
        ' Obtain an IEnumerator across all non roaming stores for the 
        ' current user
        Dim e As IEnumerator = _
        IsolatedStorageFile.GetEnumerator(IsolatedStorageScope.User) 
 
        ' Iterate through the enumerator
        While e.MoveNext(  )
 
                Dim i As IsolatedStorageFile = _
                CType(e.Current, IsolatedStorageFile)
 
                ' Display the scope of the current store
                Console.WriteLine("STORE SCOPE: {0}", i.Scope)
 
                ' Display the maximum and current size for the store
                Console.WriteLine("Current size={0}", i.CurrentSize)
 
                ' Display the assembly identity of the current store
                Console.WriteLine("Assembly ID:")
                Console.WriteLine(i.AssemblyIdentity)
 
                ' Display the domain identity of the current store if
                ' the store is isolated by domain
                If (i.Scope And IsolatedStorageScope.Domain) <> 0 Then
 
                        Console.WriteLine("Domain ID:")
                        Console.WriteLine(i.DomainIdentity)
                End If
        End While
    End Sub
End Class

11.2.3 Creating Directories

Once you have an IsolatedStorageFile object representing a store, you can create files and directories in the store. .NET's isolated storage implementation does not provide an object that represents directories; this simplifies the isolated storage class structure but also forces you to constantly work with strings that represent directory paths. The CreateDirectory method, with the following signature, creates a directory with the specified fully qualified name:

# C#

public void CreateDirectory(
    string dir
);

# Visual Basic .NET

Public Sub CreateDirectory( _
    ByVal dir As String _
)

You can create more than one level of the directory hierarchy in a single call. For example, the following statements create a directory named Dir1, as well as two subdirectories named Dir2 and Dir3 in the store represented by the iso object:

# C#

IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForDomain(  );
iso.CreateDirectory(@"Dir1\Dir2");
iso.CreateDirectory("Dir1/Dir3");

# Visual Basic .NET

Dim iso As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForDomain(  ) 
iso.CreateDirectory("Dir1\Dir2")
iso.CreateDirectory("Dir1/Dir3")

On the first call, CreateDirectory creates both the Dir1 and Dir2 directories. If you specify a directory name that already exists, as is the case with Dir1 in the second call to CreateDirectory, no error occurs. If you specify a directory name that contains illegal characters, CreateDirectory throws an IsolatedStorageException. As this code shows, you can use either the forward slash / or backward slash \ characters as the path separators.

11.2.4 Creating, Reading, and Writing Files

The IsolatedStorageFileStream class represents a file in a store. IsolatedStorageFileStream extends System.IO.FileStream and apart from its Handle property, supports all of the normal file I/O capabilities that you are familiar with, including asynchronous I/O. If you use the Handle property, it throws an IsolatedStorageException.

You do not create an IsolatedStorageFileStream through an IsolatedStorageFile object as you may expect; instead, you pass the IsolatedStorageFile instance in which you want to create or open the file to one of the IsolatedStorageFileStream constructors. The IsolatedStorageFileStream class provides eight overloaded constructors. We show the most specific IsolatedStorageFileStream constructor signature here; the other seven variations take subsets of the arguments required by this version and provide defaults for the arguments not specified:

# C#

public IsolatedStorageFileStream(
    string path,
    FileMode mode,
    FileAccess access,
    FileShare share,
    int bufferSize,
    IsolatedStorageFile isf
);

# Visual Basic .NET

Public Sub New( _
    ByVal path As String, _
    ByVal mode As FileMode, _
    ByVal access As FileAccess, _
    ByVal share As FileShare, _
    ByVal bufferSize As Integer, _
    ByVal isf As IsolatedStorageFile _
)

All of the arguments to the IsolatedStorageFileStream constructor serve the same purpose as those to the FileStream constructor, and we do not cover them in detail here. Of special interest are the first and last arguments: path and isf. The path argument is a String that contains the name of the file to create and must include the full path (within the store) of the file. If you create a file in a directory, the directory must exist before you create the file. The isf argument is a reference to the IsolatedStorageFile in which to create or open the file.

Some constructors of the IsolatedStorageFileStream class do not require you to obtain an IsolateStorageFile object first. When you call them, they automatically open a store isolated by user, assembly, and application domain as if you had first called the GetUserAssemblyForDomain method. Refer to the .NET Framework SDK documentation for details on the available constructors.

After creating or opening a file in a store, you can use the IsolatedStorageFileStream object as you would with any other FileStream object. Example 11-2 demonstrates two methods that demonstrate the simplicity with which you can read and write XML data to isolated storage—a common approach when storing user and application data. In WriteConfig, we demonstrate the creation of an XML file named Config.xml, to which we write the contents of a System.Xml.XmlDocument. In the ReadConfig method, read the Config.xml file and return a new XmlDocument created from the files contents. Consult the .NET Framework SDK documentation for details of the XmlDocument class.

Example 11-2. Reading and writing XML data to isolated storage
# C#

public static void WriteConfig(IsolatedStorageFile store,
    XmlDocument xml) {

    //Ensure there is a config directory
    store.CreateDirectory("/config");
    
    // Create or Open the Config.xml file
    IsolatedStorageFileStream str = new IsolatedStorageFileStream(
        "/config/Config.xml",
        FileMode.OpenOrCreate,
        FileAccess.Write,
        FileShare.None,
        100,
        store
    );
    
    // Write the XmlDocument to the isolated storage file
    xml.Save(str);

    // Close the Config.xml file
    str.Close(  );                        
}

public static XmlDocument ReadConfig(IsolatedStorageFile store) {
        
    // Open the Config.xml file
    IsolatedStorageFileStream str = new IsolatedStorageFileStream(
        "config/Config.xml",
        FileMode.Open,
        FileAccess.Read,
        FileShare.None,
        100,
        store
    );
    
    // Create a new XmlDocument and load the config file
    XmlDocument xml = new XmlDocument(  );
    xml.Load(str);
    
    // Close the Config.xml file
    str.Close(  );
    
    // return the XmlDocument
    return xml;
}

# Visual Basic .NET

Public Shared Sub WriteConfig(ByVal store As IsolatedStorageFile, _
ByVal xml As XmlDocument)

    'Ensure there is a config directory
    store.CreateDirectory("/config")

    ' Create or Open the Config.xml file
    Dim str As IsolatedStorageFileStream = New IsolatedStorageFileStream( _
    "/config/Config.xml",FileMode.OpenOrCreate,FileAccess.Write, _
    FileShare.None,100,store)

    ' Write the XmlDocument to the isolated storage file
    xml.Save(str)

    ' Close the Config.xml file
    str.Close(  )
End Sub

Public Shared Function ReadConfig(ByVal store As IsolatedStorageFile) _
As XmlDocument

    ' Open the Config.xml file
    Dim str As IsolatedStorageFileStream = New IsolatedStorageFileStream( _
    "config/Config.xml",FileMode.Open,FileAccess.Read,FileShare.None,100, _
    store) 

    ' Create a new XmlDocument and load the config file
    Dim xml As XmlDocument =  New XmlDocument(  ) 
    xml.Load(str)

    ' Close the Config.xml file
    str.Close(  )

    ' return the XmlDocument
    Return xml
End Function

11.2.5 Searching for Files and Directories

Isolated storage does not provide any mechanism through which you can work directly with objects that represent the individual directories within a store, but does provide search capabilities that simplify the discovery of files and directories.

The GetDirectoryNames and GetFileNames methods both return a String array containing a list of files or directories contained in a store with names that match a specified pattern. Both methods take a single String argument containing the pattern for which to search. The GetDirectoryNames and GetFileNames methods have the following signatures:

# C#

public string[] GetDirectoryNames(
    string searchPattern
);

public string[] GetFileNames(
    string searchPattern
);

# Visual Basic .NET

Public Function GetDirectoryNames( _
    ByVal searchPattern As String _
) As String(  )

Public Function GetFileNames( _
    ByVal searchPattern As String _
) As String(  )

The searchPattern argument must specify the full path of the directory in which you want to search and can include both single-character ("?") and multicharacter ("*") wildcards, but only in the final element. Table 11-4 lists some example values of searchPattern for both the GetDirectoryNames and GetFileNames methods and describes their effects.

Table 11-4. Example searchPattern values

Values

Description

GetDirectoryNames

 

"*"

Returns the names of all directories contained in the root directory

"/data/*"

Returns the names of all directories contained in the data directory

"/data??/*"

Error; wildcards can occur only in the last element

GetFileNames

 

"*"

Returns the names of all files contained in the root directory

"config/*.xml"

Returns the names of all .xml files contained in the config directory

"data/SomeApp.???"

Returns the names of all files in the data directory with the name SomeApp and any three-letter extension

We demonstrate the use of both the GetDirectoryNames and GetFileNames methods in the following section.

11.2.6 Deleting Files and Directories

You delete files and directories from a store through the methods of the IsolatedStorageFile object that represents the containing store. Both the DeleteDirectory and DeleteFile methods take a single String argument that specifies the fully qualified name of the file to delete:

# C#

public void DeleteDirectory(
    string dir
);

public void DeleteFile(
    string file
);

# Visual Basic .NET

Public Sub DeleteDirectory( _
    ByVal dir As String _
)

Public Sub DeleteFile( _
    ByVal file As String _
)

If you try to delete a directory that does not exist or you include wildcard characters in the directory name, DeleteDirectory throws an IsolatedStorageFile exception. Attempting to delete a file that does not exist also results in an IsolatedStorageFile exception, but including wildcard characters in the filename will cause a System.Argument exception.

The major difficulty in using DeleteDirectory is that the directory must be empty of files and subdirectories before you can delete it. Because you cannot specify wildcard characters to delete groups of files and directories, you have to implement the program logic necessary to delete all of the files in the directory. Example 11-3 contains a static method named DeleteDirectory, which demonstrates the techniques necessary to delete an isolated storage directory tree. DeleteDirectory takes two arguments: an IsolatedStorageFile object that represents the store containing the directory to delete, and a System.String, which specifies the fully qualified name of the directory to delete—for example, "/config/gary":

Example 11-3. Deleting an isolated storage directory tree
# C#

public static void DeleteDirectory(IsolatedStorageFile store, String root) {
    
    // Ensure we have a directory name ending in a "/" character
    String dir = root.EndsWith("/") ? root : root + "/";
        
    // Get a list of all files in the current directory, iterate 
    // through them and delete them.
    foreach (String file in store.GetFileNames(dir + "*")) {
       
        store.DeleteFile(file);
    }        

    // Get a list of all sub-directories in the current directory, 
    // iterate through them and delete them.
    foreach (String subdir in store.GetDirectoryNames(dir + "*")) {
       
        DeleteDirectory(store, dir + subdir + "/");
    }
        
    // Delete the current directory
    store.DeleteDirectory(dir);
}    

# Visual Basic .NET

Public Shared Sub DeleteDirectory(ByVal store As IsolatedStorageFile, _
ByVal root As String)

    ' Ensure we have a directory name ending in a "/" character
    Dim dir As String = IIf(root.EndsWith("/"), root, root & "/")

    ' Get a list of all files in the current directory, iterate 
    ' through them and delete them.
    Dim file As String
    For Each file In store.GetFileNames(dir + "*")

        store.DeleteFile(file)
    Next

    ' Get a list of all sub-directories in the current directory, 
    ' iterate through them and delete them.
    Dim subdir As String
    For Each subdir In store.GetDirectoryNames(dir + "*")

        DeleteDirectory(store, dir + subdir + "/")
    Next

    ' Delete the current directory
    store.DeleteDirectory(dir)
End Sub

11.2.7 Deleting Stores

To delete a store, use the Remove method of the IsolatedStorageFile class. Remove has two overloads, with the signatures shown here:

# C#
public override void Remove(  );

public static void Remove(
    IsolatedStorageScope scope
);

# Visual Basic .NET

Overrides Overloads Public Sub Remove(  )

Overloads Public Shared Sub Remove( _
    ByVal scope As IsolatedStorageScope _
)

The first overload is an instance method that takes no arguments and simply deletes the store represented by the current IsolatedStorageFile object. If you try to use the IsolatedStorageFile object after calling Remove, a System.InvalidOperation exception is thrown because the store is considered to be closed. The second Remove overload is a static method that takes an IsolatedStorageScope argument, which represents the isolation scope of the stores to delete. Table 11-5 lists the valid combination of IsolatedStorageScope values you can use for the scope argument.

Once you delete a store, its contents are not recoverable.

Table 11-5. Valid IsolatedStorageScope values for GetEnumerator

Values

Description

User

Removes all nonroaming stores for the current user

Roaming | User

Removes all roaming stores for the current user

    [ Team LiB ] Previous Section Next Section