Silverlight, Isolated Storage, RIA and Network Changes - Part II

Posted by: Malcolm Sheridan , on 9/8/2009, in Category Silverlight 2, 3, 4 and 5
Views: 21433
Abstract: In part II of this article I’ll demonstrate how to use save data locally using isolated storage, then update the database using RIA services once you’re back online.
Silverlight, Isolated Storage, RIA and Network Changes - Part II
 
In part I of this article, Using Silverlight 3 to Detect Network Changes, I showed you how easy it is to detect network changes using Silverlight. That is pretty cool on its own, but it would make more sense to show you a real world example. Well here is part II. I thought it would be nice to use the networking capabilities of Silverlight to either save changes locally using IsolatedStorage when there is no network connection, and when the network is restored, propagating those changes up to the database using RIA Services. This is a very simple application, but I’m trying to show you what is possible.
Before beginning you must install the latest RIA Services package from Microsoft. As of writing this the July 2009 version is the latest version. You can download it from here. I recommend that you also download the accompanying PDF, which provides a lot of detail, and plenty of good code samples.
To begin with open Visual Studio 2008 and choose File > New > Project > Silverlight > Silverlight Application. Select the Enable RIA Services check box:
 
NewSilverlightApplication
 
That being done I need to create a small database with a single table to hold the data. For this example I have created a database called MyNotes and a table called Note. It has a column called ID which is the primary key, and a column called Entry which will hold some text:
 
Note
 
Now that the database has been created, the next step is to add a new LINQ to SQL file to the project and call it MyNote. Add the Note table to the LINQ to SQL file:
Note_1 
Before moving on it is important to build your project. Once that’s done it’s time to add the Domain Service Class to your project and call it MyNoteService:
 
AddNewItem
 
For this example just leave the Domain Service Classes generated code as is. Our work will take place inside the Silverlight project. Open the MainPage.xaml file and add the following xaml:
 
<riaControls:DomainDataSource x:Name="dds"
QueryName="GetNotes"
                  AutoLoad="True">
<riaControls:DomainDataSource.DomainContext>
            <local:MyNoteContext />
</riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>
<StackPanel Orientation="Vertical"
Height="200"
            Width="300"
            x:Name="NetworkStatus">
<data:DataGrid ItemsSource="{Binding Data, ElementName=dds}"
            IsReadOnly="False" x:Name="dgNote"
            AutoGenerateColumns="True"
            HeadersVisibility="None" Height="35">
</data:DataGrid>
      <Button Content="Save"
                    Width="50"
                    Height="25"
                    Click="Button_Click" />
</StackPanel>
 
The DomainDataSource will be responsible for all the CRUD work, but because this application will not always be online, we’ll need to write some custom code to save the data locally when the application is offline, and then propagate those changes to the database when you’re back online. Let’s turn our attention to the code. Add the following code to the MainPage code behind:
 
C#
 
private bool Online { get; set; }
public MainPage()
{
InitializeComponent();
      Loaded += new RoutedEventHandler(MainPage_Loaded);
}
 
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
      GetNetworkStatus();
      NetworkChange.NetworkAddressChanged += new
               NetworkAddressChangedEventHandler(NetworkChange_NetworkAddressChanged);
}       
 
void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
{
GetNetworkStatus();
}
 
private void GetNetworkStatus()
{
Online = NetworkInterface.GetIsNetworkAvailable();           
}
 
VB.NET
 
Private privateOnline As Boolean
Private Property Online() As Boolean
      Get
            Return privateOnline
      End Get
      Set(ByVal value As Boolean)
            privateOnline = value
      End Set
End Property
Public Sub New()
InitializeComponent()
       AddHandler Loaded, AddressOf MainPage_Loaded
End Sub
 
Private Sub MainPage_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
       GetNetworkStatus()
       AddHandler NetworkChange.NetworkAddressChanged, AddressOf NetworkChange_NetworkAddressChanged
End Sub
 
Private Sub NetworkChange_NetworkAddressChanged(ByVal sender As Object, ByVal e As EventArgs)
GetNetworkStatus()
End Sub
 
Private Sub GetNetworkStatus()
Online = NetworkInterface.GetIsNetworkAvailable()
End Sub
 
In the code above, I have created an event handler for when the user control is loaded, which in turn creates another event handler to monitor network changes. GetNetworkStatus queries NetworkInterface.GetIsNetworkAvailable and checks whether or not a network connection is available. The result is saved to the Online property which I will use whenever the user saves data.
 
The next step is to add the code to save the changes locally. For this task I am going to use the IsolatedStorage object. Add the following code to save the data:
 
C#
 
public void SaveLocally(string filename, object obj)
{
using (var appStore = IsolatedStorageFile.GetUserStoreForApplication())
      {
using (var fileStream = appStore.OpenFile(filename, FileMode.Create))
            {
DataContractSerializer serializer = new DataContractSerializer(typeof(Note));
serializer.WriteObject(fileStream, obj);
}
}
}
 
VB.NET
 
Public Sub SaveLocally(ByVal filename As String, ByVal obj As Object)
Using appStore = IsolatedStorageFile.GetUserStoreForApplication()
Using fileStream = appStore.OpenFile(filename, FileMode.Create)
Dim serializer As New DataContractSerializer(GetType(Note))
serializer.WriteObject(fileStream, obj)
End Using
End Using
End Sub
 
In the code above IsolatedStorageFile.GetUserStoreForApplication obtains user-scoped isolated storage for use by an application that calls from the virtual host domain. The file is created, and the current Note the user is working with is serialized and saved to the isolated portion of the file system. To retrieve the data, use the code below:
 
C#
 
public Note Retrieve(string filename)
{
Note note = null;
using (var appStore = IsolatedStorageFile.GetUserStoreForApplication())
      {
            if (appStore.FileExists(filename))
            {
using (var fileStream = appStore.OpenFile(filename, FileMode.Open))
                  {
DataContractSerializer serializer = new DataContractSerializer(typeof(Note));
                        note = serializer.ReadObject(fileStream) as Note;
}
}
return note;
}
 
VB.NET
 
Public Function Retrieve(ByVal filename As String) As Note
Dim note As Note = Nothing
Using appStore = IsolatedStorageFile.GetUserStoreForApplication()
             If appStore.FileExists(filename) Then
Using fileStream = appStore.OpenFile(filename, FileMode.Open)
Dim serializer As New DataContractSerializer(GetType(Note))
                                    note = TryCast(serializer.ReadObject(fileStream), Note)
End Using
             End If
Return note
End Using
 
The main difference in the code above is that the Note is read from the isolated storage and returned as a Note object. You can create different folders to store different files, but I wanted to keep this as simple as possible. The last piece of the puzzle is to add the code that either saves the data locally or the database. Add the following to the button’s event handler:
 
C#
 
private void Button_Click(object sender, RoutedEventArgs e)
{           
if (Online)
      {
            // save to database                          
            if (DataSavedLocally)
            {
                  var note = Retrieve("test.txt");
                  CurrentNote.Entry = note.Entry;
                  DataSavedLocally = false;
}
            Context.SubmitChanges();
}
      else
      {
            // save to local storage
            SaveLocally("test.txt", CurrentNote);
            DataSavedLocally = true;
}             
}    
 
VB.NET
 
Private Sub Button_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
If Online Then
             ' save to database                          
                  If DataSavedLocally Then
                        Dim note = Retrieve("test.txt")
                         CurrentNote.Entry = note.Entry
                         DataSavedLocally = False
                  End If
                  Context.SubmitChanges()
       Else
             ' save to local storage
                  SaveLocally("test.txt", CurrentNote)
                  DataSavedLocally = True
       End If
End Sub
 
The first check when saving is to see if the application has a network connection. If it doesn’t, then the note is saved locally by calling the SaveLocally method. If the user saves data and the application is online, the code checks to see if there has been data saved locally. If there is, the note is retrieved from isolated storage. Finally the data is saved by executing the DomainContext’s SubmitChanges method.  

This is a very simple example of an online/offline application, but hopefully you can see the benefits of being able to detect network changes and act upon them using isolated storage and RIA Services.

The entire source code of this article can be downloaded over here

If you liked the article,  Subscribe to the RSS Feed or Subscribe Via Email

Malcolm Sheridan is an independent contractor who has been working with Microsoft technologies since VB4. Malcolm has worked with .NET since its inception and thoroughly enjoys ASP.NET.
 

Give a +1 to this article if you think it was well written. Thanks!
Recommended Articles
Malcolm Sheridan is a Microsoft awarded MVP in ASP.NET, a Telerik Insider and a regular presenter at conferences and user groups throughout Australia and New Zealand. Being an ASP.NET guy, his focus is on web technologies and has been for the past 10 years. He loves working with ASP.NET MVC these days and also loves getting his hands dirty with jQuery and JavaScript. He also writes technical articles on ASP.NET for SitePoint and other various websites. Follow him on twitter @malcolmsheridan


Page copy protected against web site content infringement by Copyscape


User Feedback
Comment posted by Edison on Saturday, September 19, 2009 6:34 PM
Error   5   Could not write lines to file "obj\Debug\SilverlightApplication1.Web.csproj.FileListAbsolute.txt". The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.   SilverlightApplication1.Web

Please, open ?,
Comment posted by Chakradhar on Wednesday, February 17, 2010 6:46 AM
What is the Note here... wht is the namespace of it....

Post your comment
Name:  
E-mail: (Will not be displayed)
Comment:
Insert Cancel