As stated earlier in this chapter, a local database is read-only when it is located in a XAP file. If you want to provide a prepopulated database that is writable from your app, the database must be copied by your app, from your XAP file, to isolated storage.
Like any other resource, such as an image file, an .sdf database file may be stored as content within your app’s XAP file. The app then reads the database file as a Stream
of bytes and writes the bytes to isolated storage. After the database has been copied to isolated storage, it is ready to be used by your app.
Note
To prevent the size of your project’s assembly from being unnecessarily increased by the inclusion of a database file, set the file’s Build Action to Content in the Visual Studio Properties pane. This decreases your app’s startup time because it takes less time for the CLR to load a smaller assembly. It does not, however, affect your project’s XAP file size.
Listing 29.6 shows the custom IsolatedStorageUtility
class, whose CopyApplicationResourceToIsolatedStorage
method locates an application resource and copies it as a stream to a specified location in isolated storage.
public class IsolatedStorageUtility : IIsolatedStorageUtility, ISettingsService
{
public void CopyApplicationResourceToIsolatedStorage(
string inResourceName, string outFilename)
{
ArgumentValidator.AssertNotNull(inResourceName, "inResourceName");
ArgumentValidator.AssertNotNullOrWhiteSpace(outFilename, "outFilename");
Uri uri = new Uri(inResourceName, UriKind.Relative);
string destination = outFilename;
int separatorIndex = destination.LastIndexOf("/");
if (separatorIndex == destination.Length - 1)
{
throw new InvalidOperationException(
string.Format("Destination '{0}' should not end with '/'",
destination));
}
string directory = null;
if (separatorIndex != -1)
{
directory = destination.Substring(0, separatorIndex);
}
using (Stream resourceStream = Application.GetResourceStream(uri).Stream)
{
using (IsolatedStorageFile isolatedStorageFile
= IsolatedStorageFile.GetUserStoreForApplication())
{
if (!string.IsNullOrWhiteSpace(directory)
&& !isolatedStorageFile.DirectoryExists(directory))
{
isolatedStorageFile.CreateDirectory(directory);
}
using (IsolatedStorageFileStream outStream
= isolatedStorageFile.OpenFile(
destination, FileMode.Create))
{
resourceStream.CopyTo(outStream);
}
}
}
}
...
}
A database file can then be copied from a XAP file to isolated storage in a single step:
IsolatedStorageUtility.CopyApplicationResourceToIsolatedStorage(
"/Subdirectory/XapDatabase.sdf",
"/Subdirectory/IsolatedStorageDatabase.sdf");
This can be seen in action in the unit test class named IsolatedStorageUtilityTests
, located in the downloadable sample code (see Listing 29.7). The CopyDatabaseToIsolatedStorage
test method copies an .sdf file to isolated storage and then verifies that the bytes of both files are equivalent.
The CollectionAssert.AreEquivalent
method compares the members of both collections. If all members match, the assert succeeds. The CollectionAssert
class is a part of the Windows Phone Toolkit Unit Testing Framework, discussed in Chapter 24, “Unit Testing Apps.”
[TestMethod]
public void CopyDatabaseToIsolatedStorage()
{
const string databaseName = "TestDatabase.sdf";
IsolatedStorageUtility utility = new IsolatedStorageUtility();
utility.CopyApplicationResourceToIsolatedStorage(databaseName, databaseName);
Uri uri = new Uri(databaseName, UriKind.Relative);
byte[] resourceBytes;
using (Stream resourceStream = Application.GetResourceStream(uri).Stream)
{
resourceBytes = resourceStream.ReadAllBytes();
}
Assert.IsNotNull(resourceBytes, "Resource bytes in null");
Assert.IsTrue(resourceBytes.Length > 0, "Resource bytes length <= 0.");
using (IsolatedStorageFile isolatedStorageFile
= IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream outStream
= isolatedStorageFile.OpenFile(databaseName, FileMode.Open))
{
byte[] isolatedStorageBytes = outStream.ReadAllBytes();
Assert.IsNotNull(isolatedStorageBytes);
Assert.IsTrue(isolatedStorageBytes.Length > 0);
CollectionAssert.AreEquivalent(resourceBytes, isolatedStorageBytes);
}
}
}
18.118.12.186