With the methods described throughout today's lesson, you can store data in a file in a unique path, such as c:\inetpub\wwwroot\tyaspnet21days\day13\log.txt. This is a very powerful and useful method for storage, but suffers from some drawbacks.
First, you have to know or create a unique path for every file. This isn't too much of a problem in the scenarios you've examined today, but imagine what happens when you create an ASP.NET application that must be distributed to different servers, each with its own file system structure. It can be a real pain to maintain all these different file locations.
Second, when you create files, they are vulnerable to access by other users or applications that have access to the file (anyone from a Web visitor to someone physically located at the computer). This is great for a file that keeps track of a page counter, for instance, when every person should have access to the contents, but what if you want to store personal information? It is difficult to keep track of whose information is whose.
ASP.NET's isolated storage mechanism is a way to combat all of this. Isolated storage is similar to cookies in that data is isolated by user. Each user gets her own isolated storage area. It also allows you to forget about storage locations. You don't have to worry about unique pathnames anymore. Isolated storage saves data to stores that can reside anywhere, even on the client computer like a cookie.
You need to learn a few new things before you can use isolated storage, but after that, much of this mechanism works the same as the other file access methods.
Creating Isolated Storage Locations
There are two objects you should be concerned with for isolated storage: the IsolatedStorageFile object and the IsolatedStorageFileStream object, which are similar to the File and FileStream objects I talked about earlier today. In fact, the IsolatedStorageFileStream object has the same methods and properties as the FileStream object.
Unlike the File object, however, the IsolatedStorageFile object does not represent files, but rather a storage location. Files within the storage location are represented by IsolatedStorageFileStream objects. This can be a little confusing at first, so it is important to get the objects straight in your mind.
Examine Listing 13.6, which shows you how to create a file in isolated storage.
Listing 13.6 Creating an Isolated Storage File
1:<%@ Page Language="VB" %> 2:<%@ Import Namespace="System.IO" %> 3:<%@ Import Namespace="System.IO.IsolatedStorage" %> 4: 5:<script runat="server"> 6: sub Page_Load(obj as object, e as eventargs) 7: dim stream as IsolatedStorageFileStream 8: dim writer as StreamWriter 9: dim data as string = "blue" 10: 11: stream = new IsolatedStorageFileStream("colors.txt", _ 12: FileMode.OpenOrCreate) 13: writer = new StreamWriter(stream) 14: writer.WriteLine(data) 15: writer.Close() 16: end sub 17:</script> 18: 19:<html><body> 20:</body></html>
| || |
Notice the addition of the System.IO.IsolatedStorage namespace on line 3. Don't forget to include this in your pages. On lines 7 9, you declare your variables, which include the new IsolatedStorageFileStream object. You should already be familiar with the StreamWriter object on line 8.
The next block of code should also look familiar the only new item is the use of the IsolatedStorageFileStream object. The syntax for creating this object is the same as that for creating the FileStream object. You then perform familiar operations with the StreamWriter on lines 13 and 14, and close the writer on line 15, which also closes the IsolatedStorageFileStream. That's all there is to it.
This code creates a file called colors.txt in an isolated storage location particular to the current user. If another user were to try to access this file, he wouldn't be able to, just as a user can't access another person's cookies. The locations of the saved files vary according to the operating system used, as described in Table 13.6.
Table 13.6. The Default Isolated File Storage Locations
|Operating System ||Location |
|Windows 95, 98, or Me ||c:\Windows\Local Settings\Application Data |
|Windows NT 4.0 ||c:\WinNT\Profiles\<user>\Application Data |
|Windows NT 4.0 (Service Pack 4) and Windows 2000 (upgrade from NT 4.0) ||c:\WinNT\Profiles\<user>\Local Settings\Application Data |
|Windows 2000 (clean install and upgrades from Windows 95,98, Me, and Windows NT 3.51) ||c:\Documents and Settings\<user>\Local Settings\Application Data\Microsoft |
For example, after executing Listing 13.6 on Windows 2000 (a clean install), navigate to the directory C:\Documents and Settings\Default User\Local Settings\Application Data. You should see a new folder named IsolatedStorage. Within this folder are several other folders that ASP.NET uses to keep track of what's going on, as well as the file created on line 11. Often, you won't care what occurs in these directories, but it is helpful to know where the files are physically located.
Accessing Isolated Storage
Isolated storage data is isolated by two different methods: by user and assembly, or by user, assembly, and domain. The first method means that a store will be created for each application a user uses. For example, a storage file created by user A in application A will not be accessible by the same user in application B. The second method also adds the application domain into the equation. For ASP.NET, this is the URL for your application.
Recall from Day 2 that every ASP.NET page is compiled into a dynamically generated assembly. This means that under normal circumstances, no two separate ASP.NET pages will use the same assembly, which in turn means that no two separate ASP.NET pages can access the same isolated storage location. Figure 13.9 illustrates this concept.
Figure 13.9. The same user, accessing two different ASP.NET pages in the same application, will not be able to access the same store.
You can use the IsolatedStorageFileStream to easily read from isolated storage. Listing 13.7 demonstrates this.
Listing 13.7 Reading from Isolated Storage with the IsolatedStorageFileStream
1:<%@ Page Language="VB" %> 2:<%@ Import Namespace="System.IO" %> 3:<%@ Import Namespace="System.IO.IsolatedStorage" %> 4: 5:<script runat="server"> 6: sub Page_Load(Sender as Object, e as EventArgs) 7: dim stream as new IsolatedStorageFileStream _ 8: ("colors.txt", FileMode.OpenOrCreate) 9: dim objReader as new StreamReader(stream) 10: 11: while objReader.Peek() > -1 12: Response.Write(Server.HTMLEncode _ 13: (objReader.ReadLine) & "<br>") 14: end while 15: objReader.Close 16: end sub 17:</script> 18: 19:<html><body> 20: <asp:Label runat="server" /> 21:</body></html>
This listing will look familiar because there are no new methods. It should print out the word blue, which you stored in your storage location in the previous listing.
Note that you might not see any output from this listing. Recall that two different ASP.NET pages cannot access the same isolated store. Therefore, Listing 13.7 should not be able to access the store from Listing 13.6. Placing Listings 13.6 and 13.7 together solves the problem (the same goes for Listings 13.6 and 13.8).
Reading from isolated storage with the IsolatedStorageFile object is a bit different. You must first obtain the reference to the files in isolated storage, and then you can use the IsolatedStorageFileStream object to do as you want with the files. Listing 13.8 shows this procedure.
Listing 13.8 Reading from Isolated Storage with the IsolatedStorageFile Object
1:<%@ Page Language="VB" %> 2:<%@ Import Namespace="System.IO" %> 3:<%@ Import Namespace="System.IO.IsolatedStorage" %> 4: 5:<script runat="server"> 6: sub Page_Load(Sender as Object, e as EventArgs) 7: dim objISOFile as IsolatedStorageFile = _ 8: IsolatedStorageFile.GetUserStoreForDomain() 9: 10 lblMessage.Text = "<b>Files:</b> " 11: dim intCount = Ubound(objISOFile.GetFileNames("*.*")) 12: for i = 0 to intCount 13: lblMessage.Text += objISOFile.GetFileNames _ 14: ("*.*")(i) & "<br>" 15: next 16: 17: lblMessage.Text += "<b>Assembly: </b>" & _ 18: objISOFile.AssemblyIdentity.ToString & "<br>" 19: lblMessage.Text += "<b>Domain: </b>" & _ 20: objISOFile.DomainIdentity.ToString & "<br>" 21: lblMessage.Text += "<b>Current Size: </b>" & _ 22: objISOFile.CurrentSize.ToString & "<br>" 23: lblMessage.Text += "<b>Max Size: </b>" & _ 24: objISOFile.MaximumSize.ToString & "<br>" 25: end sub 26:</script> 27: 28:<html><body> 29: <asp:Label runat="server" /> 30:</body></html>
| || |
On line 7, you instantiate an IsolatedStorageFile object. The IsolatedStorageFile.GetUserStoreForDomain method returns the IsolatedStorageFile that is particular for the current user, assembly, and domain. The IsolatedStorageFile.GetUserStoreForAssembly method returns only the storage location for a particular user and assembly.
The GetFileNames method returns an array of filenames that matches a specified search string; "*.*", in this case. Lines 12 15 loop through this array and print out the names to a label control. The GetDirectoryNames method performs a similar operation, and also uses a search string to filter the results.
Finally, lines 17 24 print out the properties of the isolated storage area. The AssemblyIdentity property returns a URL that specifies the assembly that this storage location is particular to (this is a dynamic assembly .NET generates for your Web application). DomainIdentity specifies the domain associated with this storage location similar to the domain property for cookies. The CurrentSize and MaxSize properties specify the size dimensions of the current user's data store in bytes. Figure 13.10 shows the output of this code.
Figure 13.10. Viewing isolated storage information with the IsolatedStorageFile object.
Figure 13.10 shows the dynamic assembly generated by ASP.NET for your application, the domain (which reflects the Web site domain), and the current and max sizes of the storage area.
You can create an IsolatedStorageFileStream around the IsolatedStorageFile and use a StreamReader to access the contents, as was done earlier:
dim objISOFile as IsolatedStorageFile = _ IsolatedStorageFile.GetUserStoreForDomain() dim stream as new IsolatedStorageFileStream _ ("options.txt", FileMode.OpenOrCreate, objISOFile)