Use Isolated Storage for Stateful Network-deployable .NET Components

Use Isolated Storage for Stateful Network-deployable .NET Components

solated storage represents a subset of the file system that partially trusted applications can access to perform their private I/O operations. Introduced to preserve the integrity and the functionality of the whole operating system, isolated storage exploits the principle of the sandbox?isolate to prevent damage and malicious code. A set of stream-based classes let you work with such a storage system in an extremely simple and immediate way.

In .NET, not all applications run with the same set of security permissions. Security permissions represent the key to access critical system resources such as the file system, the registry, the clipboard, and the printer. Applications that attempt to access these resources without a valid authorization simply run into an exception. The mechanism behind security permissions is called Code Access Security (CAS) and represents the .NET answer to the growing demand for software security. CAS works by granting permissions to each assembly that is loaded in the CLR. The permission set for an assembly stems from the evidence that the assembly itself provides. The evidence defines the set of information that constitutes input for security decisions. This information includes any digital signatures the assembly may have and the location from which the assembly is accessed.

Just the location of download is a critical factor for applications. The set of permissions granted, in fact, changes considerably if the assembly is accessed locally or maybe remotely from a Web site. As you can guess, location dependent permissions pose a number of issues to developers that are going to write network-deployable classes. In this article, after a brief introduction to fully and partially trusted applications, I’ll focus on isolated storage?namely, a feature of the .NET Framework that elegantly works around the file system limitations for network-based applications, including ASP.NET applications.

Trusted Applications
While loading a managed assembly on behalf of a running application, the CLR is called to determine the set of permissions associated with that assembly. The CLR bases any decision both on the privileges of the currently logged user and the location from which the assembly is going to be downloaded. As a result, the permissions allowed to a certain assembly may prevent the code to perform certain necessary but potentially harmful operations such as writing files or accessing the registry. Applications automatically limited in their functionality for security reasons are said to be partially trusted applications.

When applications attempt to perform an operation not allowed by the ongoing security policy, the event is signaled with an exception of type SecurityException. The CLR prompts the user with a dialog box like the one shown in Figure 1.

The Case of ASP.NET Applications
Just a few weeks before releasing version 1.0 of the .NET Framework, Microsoft decided to change the default account for the ASP.NET runtime process. Unlike ASP, ASP.NET does not run applications within the context of the LOCALSYSTEM account. ASP.NET applications are considered partially trusted applications and, subsequently, pages accessing the file system explicitly need to be granted write permissions to operate safely and effectively. How can you work around this I/O limitation? (See Sidebar: Security Zones)

One thing you can do is change the security permissions on the folder that contains the ASP.NET application. You must do this once during the setup of the application. Here’s a step-by-step guide.

  1. Open the folder with Windows Explorer.
  2. Right-click and select the Properties menu item.
  3. From the subsequent tabbed view, pick the Security page.
  4. Add the ASP.NET account to the list of accounts enabled to operate on the folder by clicking the Add button and selecting ASPNET from the list of available users. (See Figure 3).
  5. Next, return to the previously selected Security tab, highlight the newly added ASPNET account and add write permissions. (See Figure 4).

Figure 3: Select the ASPNET user account and click Add to be able to edit the default permissions.
Figure 4:Select the ASPNET account and edit the permissions accordingly.

After this treatment the ASP.NET application based in that physical folder will be able to create and update local files.

Normally an ASP.NET application needs to create local files to park some data or to persist some settings. If the name of the file is known, not subject to change, and a default copy of the file is provided at setup time, you could also apply the algorithm above to the individual file rather than to the whole folder.

In other situations ASP.NET applications need to create temporary files that don’t survive the session or even the single request. In this case you can consider employing a simpler trick?using in-memory streams.

The MemoryStream class works in much the same way that a disk file stream does. The key difference is that MemoryStream creates a stream whose backing store is memory rather than a disk file. Let’s compare the code necessary to save a file to a file stream and to a memory stream.

   ' Use FileStream to create a file   Dim file As StreamWriter   file = New StreamWriter(fileName, _      FileMode.CreateNew)   WriteContents(file)   file.Close()      ' Use MemoryStream to create a memory buffer   Dim ms As MemoryStream   ms = New MemoryStream()   WriteContents(ms)   ms.Close()

The MemoryStream class encapsulates its data into an array of bytes and makes it available only in that form. You can write strings to a MemoryStream object only after you convert them to an array of unsigned characters. Unfortunately no method on the String class provides that capability. To do this job you must resort to the GetBuffer method of the Encoding class.

   Dim s As String = "Hello, world!"   ms.Write(Encoding.ASCII.GetBytes(s), _      0, s.Length)

It is also easy to read back strings from a MemoryStream object. In this case you use the GetString method of the Encoding class, as shown below.

   ' GetBuffer returns the contents of the stream   Dim buf As String   buf = Encoding.ASCII.GetString(ms.GetBuffer())

While the previously discussed trick?changing the permissions on a file or a folder?is just a hack, memory streams represents an interesting option because they can reduce the need for temporary buffers and files in an application.

Let’s make a more general consideration about partially trusted applications. The CAS infrastructure prohibits them from accessing the file system to avoid the risk that they could perform malicious code. However, one thing is getting a full access to the file system and all another one is persisting some user-defined bytes to disk. The second option still requires that the application accesses the file system, but?that’s the point?not necessarily the whole file system. This rather straightforward observation is at the root of the CAS feature called isolated storage.

(See Sidebar: When You Shouldn’t Use Isolated Storage)

What’s Isolated Storage, Anyway?
Isolated storage represents an assembly-specific virtual file system that is managed using the facilities of the local file system. Access to the isolated storage is always restricted to the user who created it. The idea is that the code accesses paths relative to an isolated sub file system. The high-level code simply works with streams that take regular file names. Those streams, though, read and write files located in a sandboxed portion of the file system that the system transparently manages. Isolated storage doesn’t accept absolute file names and manages to assign a distinct (and identity-based) file system subtree to each client. Figure 5 shows the architecture of isolated storage for ASP.NET applications.

Using Isolated Streams
The IsolatedStorageFile object exposes a few methods to manipulate files and directories. In particular, the CreateDirectory method lets you create a new directory in the store.


You can indicate multiple levels of directories and CreateDirectory will ensure that the specified path exists when it returns. You read, write, and create files using a particular flavor of stream?the IsolatedStorageFileStream class. The file name must be relative and cannot contain any drive information. Look at this example:

   Dim stm As IsolatedStorageFileStream   stm = New IsolatedStorageFileStream(file, _      FileMode.Create, iso)   Dim s As String = "Hello, world!"   stm.Write(Encoding.ASCII.GetBytes(s), _      0, s.Length)   stm.Close()

You use the file stream API to create a file. The file stream API is based on the programming interface of the FileStream class from which the IsolatedStorageFileStream class is derived. Once you hold an IsolatedStorageFileStream object you can use it to work with a StreamReader or a StreamWriter object, both of which provide an easier and more programmer-friendly set of methods. Using StreamReader and StreamWriter you can read and write to a file in a store as you would to any other file.

   Dim reader As StreamReader   reader = New StreamReader(stm)   Console.WriteLine(reader.ReadToEnd())   reader.Close()

Although the isolated storage is a miniaturized version of the operating system’s file system, it does not provide a rich programming interface. Isolated storage provides for the key tasks but not always through powerful and easy-to-use tools. If you want to test to make sure a given file exists before you overwrite it you must run a For-Each statement on an array of strings. Here is how:

   Dim filenames As String()   filenames = iso.GetFileNames("test.txt")   Dim file As String   For Each file In filenames      If file = "test.txt" Then         Console.WriteLine("Already exists!")         Exit Sub      End If   Next

GetFileNames on the IsolatedStorageFile class returns an array of strings filled with all the file names found in the specified pattern. GetFileNames takes an expression that may contain wildcard characters such as ? or *. Wildcards are permitted only in the file name portion of the expression. You cannot use wildcards to indicate a directory path. The returned array contains only the name of items found?that’s why you can’t perform your search on multiple paths. Similarly, GetDirectoryNames selects all directories in the isolated storage that match the pattern. Both methods require an instance of the Store object (they are not static methods) and don’t work recursively on the subfolders of the specified folder.

DeleteDirectory and DeleteFile are instance methods of the IsolatedStorageFile class that allow you to remove undesired storage directories and files. These Delete methods do not accept wildcards. To remove the whole store you use the Remove method. It is important that you remove unneeded files and directories because the disk reserved for isolated storage is not unlimited. Administrators must tune the quotas of disk storage allocated to each single store. Two read-only long properties?MaximumSize and CurrentSize?let developers foresee in advance whether a given call may fail due to space constraints. Notice that quotas are assigned on a per-evidence basis, which means that the same assembly can receive different quota if run from an intranet rather than from the Internet.

Isolated storage is a built-in mechanism of .NET security that let potentially unsecure applications safely access the disk and the local file system to perform simple writing operations. The idea behind isolated storage is the sandbox?the same that secures Java applications within the boundaries of the Java virtual machine. Isolated storage provides full disk access to applications but below isolated file system subtrees. Partially trusted applications can use isolated storage to persist data without the risk of performing malicious operations against sensitive parts of the operating system. Writing partially trusted applications is a delicate art that goes far beyond the functionality of isolated storage. But that is another story and probably another article!

See also  Comparing different methods of testing your Infrastructure-as-Code

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist

©2024 Copyright DevX - All Rights Reserved. Registration or use of this site constitutes acceptance of our Terms of Service and Privacy Policy.