为 Xamarin.Forms 移动应用启用脱机同步

概述

本教程介绍适用于 Xamarin.Forms 的 Azure 移动应用的脱机同步功能。 脱机同步允许最终用户与移动应用进行交互-查看、添加或修改数据,即使没有网络连接也是如此。 更改存储在本地数据库中。 设备重新联机后,这些更改将与远程服务同步。

本教程基于在完成教程 [创建 Xamarin iOS 应用] 时创建的移动应用的 Xamarin.Forms 快速入门解决方案。 适用于 Xamarin.Forms 的快速入门解决方案包含支持脱机同步的代码,只需启用该代码即可。 在本教程中,将更新快速入门解决方案以启用 Azure 移动应用的脱机功能。 我们还在应用中高亮显示离线专用代码。 如果不使用下载的快速入门解决方案,必须将数据访问扩展插件包添加到项目中。 有关服务器扩展包的详细信息,请参阅 使用适用于 Azure 移动应用的 .NET 后端服务器 SDK

若要了解有关脱机同步功能的详细信息,请参阅主题 Azure 移动应用中的脱机数据同步

在快速入门解决方案中启用脱机同步功能

脱机同步代码通过使用 C# 预处理器指令包含在项目中。 定义 OFFLINE_SYNC_ENABLED 符号后,这些代码路径将包含在生成中。 对于 Windows 应用,还必须安装 SQLite 平台。

  1. 在 Visual Studio 中,右键单击解决方案 >“管理解决方案的 NuGet 包...”,然后搜索并安装解决方案中所有项目的 Microsoft.Azure.Mobile.Client.SQLiteStore NuGet 包。

  2. 在解决方案资源管理器中,打开名称包含 Portable 的项目中的 TodoItemManager.cs 文件,这是一个可移植类库项目,然后取消注释以下预处理器指令:

     #define OFFLINE_SYNC_ENABLED
    
  3. (可选)若要支持 Windows 设备,请安装以下 SQLite 运行时包之一:

  4. (可选)在每个 Windows 应用项目中,右键单击 “引用>添加引用...”,展开 Windows 文件夹 >扩展。 启用适用于 Windows 的相应 SQLite SDK 和适用于 Windows 的 Visual C++ 2013 Runtime SDK。 SQLite SDK 名称因每个 Windows 平台而略有不同。

查看客户端同步代码

下面简要概述了指令中的 #if OFFLINE_SYNC_ENABLED 教程代码中已包含的内容。 脱机同步功能位于可移植类库项目中TodoItemManager.cs项目文件中。 有关该功能的概念性概述,请参阅 Azure 移动应用中的脱机数据同步

  • 在执行任何表操作之前,必须初始化本地存储。 本地存储数据库使用以下代码在 TodoItemManager 类构造函数中初始化:

      var store = new MobileServiceSQLiteStore(OfflineDbPath);
      store.DefineTable<TodoItem>();
    
      //Initializes the SyncContext using the default IMobileServiceSyncHandler.
      this.client.SyncContext.InitializeAsync(store);
    
      this.todoTable = client.GetSyncTable<TodoItem>();
    

    此代码使用 MobileServiceSQLiteStore 类创建新的本地 SQLite 数据库。

    DefineTable 方法在本地存储中创建一个表,该表与提供的类型的字段匹配。 该类型不必包括远程数据库中的所有列。 可以存储列的子集。

  • TodoItemManager 中的 todoTable 字段是 IMobileServiceSyncTable 类型,而不是 IMobileServiceTable。 此类使用本地数据库执行所有创建、读取、更新和删除(CRUD)表操作。 通过调用 IMobileServiceSyncContext 上的 PushAsync,决定何时将这些更改推送到移动应用后端。 同步上下文通过跟踪和推送客户端应用在调用 PushAsync 时修改的所有表中的更改来帮助保留表关系。

    调用以下 SyncAsync 方法以与移动应用后端同步:

      public async Task SyncAsync()
      {
          ReadOnlyCollection<MobileServiceTableOperationError> syncErrors = null;
    
          try
          {
              await this.client.SyncContext.PushAsync();
    
              await this.todoTable.PullAsync(
                  "allTodoItems",
                  this.todoTable.CreateQuery());
          }
          catch (MobileServicePushFailedException exc)
          {
              if (exc.PushResult != null)
              {
                  syncErrors = exc.PushResult.Errors;
              }
          }
    
          // Simple error/conflict handling.
          if (syncErrors != null)
          {
              foreach (var error in syncErrors)
              {
                  if (error.OperationKind == MobileServiceTableOperationKind.Update && error.Result != null)
                  {
                      //Update failed, reverting to server's copy.
                      await error.CancelAndUpdateItemAsync(error.Result);
                  }
                  else
                  {
                      // Discard local change.
                      await error.CancelAndDiscardItemAsync();
                  }
    
                  Debug.WriteLine(@"Error executing sync operation. Item: {0} ({1}). Operation discarded.",
                      error.TableName, error.Item["id"]);
              }
          }
      }
    

    此示例对默认同步处理程序使用简单的错误处理。 实际应用程序将使用自定义 IMobileServiceSyncHandler 实现来处理各种错误,例如网络条件和服务器冲突。

脱机同步时需注意的事项

在此示例中,仅在启动时以及请求同步时调用 SyncAsync 方法。 若要在 Android 或 iOS 应用中启动同步,请向下拉取项列表;对于 Windows,请使用 “同步 ”按钮。 在实际应用程序中,还可以在网络状态更改时触发同步触发器。

对上下文跟踪的具有挂起的本地更新的表执行拉取时,该拉取作会自动触发前面的上下文推送。 刷新、添加和完成此示例中的项时,可以省略显式 PushAsync 调用。

在提供的代码中,查询远程 TodoItem 表中的所有记录,但也可以通过将查询 ID 和查询传递给 PushAsync 来筛选记录。 有关详细信息,请参阅 Azure 移动应用中的 脱机数据同步中的 增量同步 部分。

运行客户端应用

启用脱机同步后,请在每个平台上至少运行一次客户端应用程序,以填充本地存储数据库。 稍后,模拟脱机方案,并在应用脱机时修改本地存储中的数据。

更新客户端应用的同步行为

在本节中,使用后端的无效的应用程序 URL 修改客户端项目以模拟离线场景。 或者,可以通过将设备移动到“飞行模式”来关闭网络连接。添加或更改数据项时,这些更改保存在本地存储中,但在重新建立连接之前不会同步到后端数据存储。

  1. 在解决方案资源管理器中,从 可移植 项目打开Constants.cs项目文件,并将值 ApplicationURL 更改为指向无效 URL:

     public static string ApplicationURL = @"https://your-service.azurewebsites.net/";
    
  2. 可移植项目打开TodoItemManager.cs文件,然后在SyncAsynctry...catch块中为基类Exception添加一个catch。 此 catch 块将异常消息写入控制台,如下所示:

         catch (Exception ex)
         {
             Console.Error.WriteLine(@"Exception: {0}", ex.Message);
         }
    
  3. 生成并运行客户端应用。 添加一些新项。 请注意,每次尝试与后端同步时,都会在控制台中记录异常。 这些新项仅存在于本地存储中,直到可以推送到移动后端。 客户端应用的行为如同已连接到后端,支持所有创建、读取、更新、删除(CRUD)操作。

  4. 关闭应用并重启它,以验证你创建的新项是否持久保存到本地存储中。

  5. (可选)使用 Visual Studio 查看 Azure SQL 数据库表,以查看后端数据库中的数据未更改。

    在 Visual Studio 中,打开 服务器资源管理器。 导航到您的 Azure SQL 数据库 ->。 右键单击您的数据库,然后选择“在 SQL Server 对象资源管理器 中打开”。 现在可以浏览到 SQL 数据库表及其内容。

更新客户端应用以重新连接移动后端

在本部分中,将应用重新连接到移动后端,该后端模拟应用返回到联机状态。 执行刷新手势时,数据将同步到移动后端。

  1. 重新打开Constants.cs。 将applicationURL更改为指向正确的 URL。

  2. 重新生成并运行客户端应用。 启动后,应用会尝试与移动应用后端同步。 验证调试控制台中是否未记录任何异常。

  3. (可选)使用 SQL Server 对象资源管理器或 REST 工具(如 Fiddler 或 Postman)查看更新的数据。 请注意,数据已在后端数据库和本地存储之间同步。

    请注意,数据已在数据库和本地存储之间同步,并包含应用断开连接时添加的项。

其他资源