Feeds:
Posts
Comments

Posts Tagged ‘offline’

In the last two parts of this session I have shown how to develop Silverlight application that shows information from a database in occasion connected environment. In this last part I will show you how to manage updates (including inserting and deleting records) and synchronizing them back into the database.

The first step is to make sure we are working with the relevant DomainContext object and to apply all the updates to the offline/online DomainContext, depending on the application’s status. To accomplish this I have created a factory method that checks the application’s status and returns the relevant DomainContext. This method should be used whenever we need a DomainContext object in Silverlight projects.

public static NorthwindDomainContext GenerateNewNorthwindDomainContext()
{
    NorthwindDomainContext northwindDomainContext;
    if (OfflineHelper.IsApplicationOnline)
    {
        northwindDomainContext = new NorthwindDomainContext();
    }
    else
    {
        northwindDomainContext = 
          (NorthwindDomainContext)DomainContextExtension.
                    GetOfflineDomainContext(typeof(NorthwindDomainContext));
    }

    return northwindDomainContext;
}

The second step is submitting the changes. To accomplish that, we will need to check the application status; if it is online we should use the out of the box SubmitChanges method and if it is offline, we just call the OCSaveAsOfflineDomainContext that we implemented in the previous parts. Since the Entity object is tracing all the changes, we do not need to do anything except serialize the updated DomainContext to the offline storage. To simplify the operation I created this extension method:


public static Task OCSubmitChangesAsync(this DomainContext source)
{
    if (OfflineHelper.IsApplicationOnline)
    {
        return source.SubmitChangesAsync();
    }
    else
    {
        return TaskEx.Run(() =>
        {
            source.OCSaveAsOfflineDomainContext();
        });
    }
}

The third and last step is synchronizing with the database when the application becomes online.  All we need is to call the SubmitChanges on the offline DomainContext. Although the MSDN sample that enables serializing RIA DomainContext objects fit the job, it still required fixing some bugs to make it work properly (I attached the final code at the button of the post). Again, I warp it up with an extension method:

public static Task OCSyncWithOnlineServiceAsync(this DomainContext source)
{
    Task result = null;
    if (OfflineHelper.IsApplicationOnline)
    {
        DomainContext offlineDomainContext = 
             GetOfflineDomainContext(source.GetType());
        try
        {
            result = offlineDomainContext.SubmitChangesAsync();
        }
        catch (Exception ex)
        {
            HandleSyncErrors(ex);
        }
    }

    return result;
}

An example of using the above methods for doing offline updating, would look something like this:

NorthwindDomainContext domainContext = 
          DomainContextFactory.GenerateNewNorthwindDomainContext();

await this.domainContext.LoadAsync(this.domainContext.GetCustomersQuery());
this.domainContext.OCSaveAsOfflineDomainContext();

OfflineHelper.IsApplicationOnline = false;

domainContext = DomainContextFactory.GenerateNewNorthwindDomainContext();
// Do some update on domainContext objects...

OfflineHelper.IsApplicationOnline = true;
await this.domainContext.OCSyncWithOnlineServiceAsync();

In addition, I have also attached a simple application that demonstrates the use of this framework. Notice that you can take the application offline, make changes, close and open the application and the changes will still be there. The application is also able to run out of the browser so you will be able to run this application even after the web server and the SQL server are unavailable.

Summary: To convert your application to support offline scenarios you will need to follow these steps:

  1. Download and install the Microsoft Visual Studio Asynchronous Framework.
  2. Add reference to the SilverlightOccasionallyConnected DLL.(attached to this post)
  3.  Create a factory method as demonstrated, to create DomainContext and use only this method throughout the Silverlight projects.
  4. Use the OCLoadAsync and OCSubmitChangesAsync to query and submit your changes respectively.
  5. Make sure that the filter and order-by logic are located in the Silverlight projects and not on the Server-side project.
  6. Add to your application this functionalities :
    1. An offline/online indication
    2. An option to generate offline copy of the database using the OCSaveAsOfflineDomainContext function. Load all the data that your application will need access to in offline mode before calling this method.
    3. An option to synchronize using the OCSyncWithOnlineServiceAsync function.

Source Code for this article

Read Full Post »

I got a request to build an internet application that will also be available offline; The user “checks out” part of the database to the client, works offline and checks it in when going back online.

To implement this request I decided to use Silverlight built-in out-of-browser application, RIA services for accessing the remote database and the MSDN sample that enables serializing RIA DomainContext objects to an isolated storage, so I can save database tables locally(part of the “Authentication quick-start” example).

The challenge with the above is that every query against the database requires checking if the application is online or offline and writing a duplicate Data access code for each scenario. The solution I used was to write a helper code that will enable writing one data access code regardless of the application status (online/offline).

For example you can write in your view model the following code:

private AdventureWorksLTDomainContext domainContext =
                              new AdventureWorksLTDomainContext();
this.Customers = await this.domainContext.OCLoadAsync(
                           this.domainContext.GetCustomersQuery());

Things to notice:

  1. The method OCLoadAsync will check the application connectivity status. If it is online it will execute the RIA service against the remote server and if it is offline it will load the information from the isolated storage.
  2. I am using the Async framework (still in CTP) to load the query. For more detail on using Async framework with RIA service please refer to this article.
  3. The query can be customized on the fly, for example the following line is also valid:
    this.Customers = await this.domainContext.OCLoadAsync(
      from customer in this.domainContext.GetCustomersQuery()
      where customer.FirstName.StartsWith(this.Prefix)
      orderby customer.FirstName, customer.LastName
      select customer );
    
  4. Given the way RIA is implemented, only the final complete query is executed against the Database.
  5. The implementation of the offline support will not include any code rules in the domain service methods. The assumption is that your domain service methods will basically return all entities for a specific type. You can add code rules to the domain service, for example security trimming;  The offline version will not include these code rules, however the local storage will only contain the records that the user had access to last time they were online..

Before you will be able to access offline storage you will need to create one. This is also an easy task with the OCSaveAsOfflineContext method. Just execute the following code when the application is online:

await this.domainContext.LoadAsync(
                    this.domainContext.GetCustomersQuery());
this.domainContext.OCSaveAsOfflineDomainContext();

Things to notice:

  1. The method LoadAsync returns the result of the query but also populates the DomainContext with the result, so by saving the domaincontext to the Isolate Storage we can access the information later when the application is offline.
  2. You will need to load all the queries you like to save with the same domainContext and then use the OCSaveAsOfflineDomainContext method to save local version of your database in the Isolated Storage.

To use this solution follow these steps:

  1. Create normal Silverlight project with Entity framework model and RIA services (if you’re not familiar with RIA you can check this link).
  2. Install the Async Framework and add reference to the AsyncCtpLibrary_Silverlight DLL.
  3. Add reference to the SilverlightOccasionallyConnected Dll  download available at the bottom of this article.
  4. Add using-statement to ‘SilverlightOccasionallyConnected” to have access to the extension methods for the DomainContext class.
  5. Start writing your class.

In Part II,  I Will explain in more detail the implementation of the DomainContext extension methods.

Source Code for this article

Read Full Post »