我过去曾将 Microsoft Sync Framework 用于类似的 N-Tier 偶尔连接的客户端,并且效果很好。自从我上次使用它以来,它一直在发展,但我认为它满足了您的要求。
WCF
在 WCF 上运行良好,这就是我们使用它的方式。 (How to: Configure N-Tier Synchronization)
应该有增量同步
同步服务可以很好地做到这一点,但您可能需要在同步表中添加时间戳。您的客户端数据库(在我的例子中是 SQL Server CE 数据库)保存上次同步时使用的最后一个时间戳,然后它将使用它来获取在下一次同步期间更改的所有内容。
可以将更改推送到服务器
我们又这样做了。有很多钩子可以在服务器上提供自定义逻辑来验证数据。
离线访问/存储信息
在完全断开连接的情况下可以正常工作(前提是用户已经先同步了他们的数据)。见Offline Scenarios。
可以进行完全重新同步(缓存损坏或新计算机)
保存所有同步信息的是客户端数据库(如果您愿意,您可以将有关客户端已同步的内容的信息放到服务器上)。如果您删除本地数据库,则客户端将执行完全同步。
服务端的数据提供者是Entity Framework
这不是我使用它的方式,但同步提供程序是完全可定制的。我们本来打算做一个 NHibernate 的,但是问问自己为什么要这样做。开箱即用的同步服务将允许您使用存储过程或直接表查询来推送和拉取数据。这很容易设置,因为您可能使用大量数据,所以运行速度非常快,并且数据很容易跨 WCF 边界同步(尽管我们确实从 xml 格式化程序切换到二进制格式化程序以获得更好的性能)。
我们发现只是因为我们在服务器上使用了实体,它们在客户端上不一定有意义,因此我们在客户端上有了一组全新的实体。这也意味着我们在存储过程中剥离了客户端不需要的数据。同样,这很容易,您不需要弄脏 ADO.net。然后,一旦数据在客户端上,我们使用 NHibernate 读取和写入本地数据库。
Building Custom Sync Providers for the Microsoft Sync Framework
我需要重复使用当前的自定义身份验证
如果您的意思是 WCF 自定义身份验证,那么可以,因为我们有自己的 WCF 自定义安全令牌,它运行良好,没有任何影响。
奖励:某些类型有特殊的同步(例如,我有一个包含小文件的数据库,但在客户端,文件必须直接放在文件夹中)
简短的回答我不知道,因为他们是新框架中的文件同步提供程序,我没有使用过,但您还有其他两个选择。
在客户端同步期间,您实际上可以挂钩到数据将被放入表中的位置,您有机会提取二进制数据并将其写入文件系统而不是数据库。
从同步中排除文件二进制数据,并在同步后使用另一个进程拉取此数据。我们这样做是因为我们拉下的包非常大,所以我们使用初始同步来拉下“元数据”,然后我们使用称为 BITS 的东西,它是 Windows 的一部分来异步拉下文件。
Introduction to Microsoft Sync Framework File Synchronization Provider
[更新]
针对cmets提出的问题。
-
我的应用程序应该适用于同一台计算机上的不同用户。就我而言,我使用隔离存储来保证它们可以在不同的位置工作,这可以通过 SQL Server CE 实现吗?
我们的应用程序是通过 ClickOnce 部署的,它将为每个用户提供单独的应用程序安装,但我认为这不是所要求的。 SQL CE 只是一个内存数据库,您将SqlCeEngine 指向您要加载的数据库文件,这样隔离存储就完美了。
-
据我所知,SQL Server CE 就像 SQLite,你如何管理架构创建?
如果需要,您可以让 Snyc Services 为您创建数据库架构,这足以让您继续前进,但从长远来看,您可能不得不在某个时候更改架构。这可能会在您进行升级时进行,因此您最好尽早考虑它。我通过不将数据库视为属于同步服务而是将其视为同步服务被告知它可以使用的方式来处理这个问题。
当我们的应用程序启动时,它会做一些内务处理,例如在数据库不存在时创建数据库,或者在应用程序刚刚升级时运行数据库脚本。
-
你知道是否有这个 N 层同步的类实现示例吗?我需要看看我必须实现哪些接口。
当前的稳定版本是 2.1,我在 2.0 发布时使用它,所以我所有的工作都在 1.0 中。这是 MSDN 上Microsoft Sync Framework 2.1 api 的链接。我必须使用 1.0 文档来查找用于驱动 WCF 接口的示例,所以我不知道事情发生了多大变化,但您可以使用 this 开始,它将接口定义为:
[服务合同]
公共接口 IServiceForSync
{
[操作合同()]
SyncContext ApplyChanges(SyncGroupMetadata groupMetadata, DataSet dataSet, SyncSession syncSession);
[OperationContract()]
SyncContext GetChanges(SyncGroupMetadata groupMetadata, SyncSession syncSession);
[OperationContract()]
SyncSchema GetSchema(Collection<string> tableNames, SyncSession syncSession);
[OperationContract()]
SyncServerInfo GetServerInfo(SyncSession syncSession);
}
我想每种数据类型只有一个服务?
不,正如您从上面看到的那样,只有一项服务。同步的内容取决于您在服务器上公开的内容以及客户端想要参与的内容。例如,我们有两个客户端,一个只对一小部分数据感兴趣并且只参与同步几个表(称为一个SyncTable),另一个同步了所有的表。
还有一个SyncGroup 的概念,它们由相关的更改组成,这些更改应该以事务方式持久化,因为它们都是相关的,即如果一个失败,它们都会失败。您还可以单独同步组,而无需同步所有内容。
- 我可以只同步与用户相关的数据吗?
当然。当您进行同步时,您会传递一个SyncParameter,其中包含可用于过滤返回给客户端的数据的值。 How to: Filter Rows and Columns.