V minulém dílu jsme si ukázali co Sync Framework je a jak v obrysech funguje. Dnes si ukážeme, jak jednoduché je vytvořit aplikaci za pomoci těchto objektů.
reklama
Pokud pomineme synchronizace obsahu databází, které jsou velmi často terčem otázek na různých fórech, můžeme s jistotou říci, že synchronizace adresářů je velmi častý úkol. Za pomoci Sync Frameworku takovouto funkcionalitu rychle vyrobíme a bude ještě značně efektivní.
Předpokládám, že jste si stáhli odpovídající balíček a nainstalovali jej. Seznam assembly, které nyní můžete referencovat, by se měl rozrůst o několik nových – Microsoft.Synchronization.*. Do projektu si přidáme Microsoft.Synchronization a Microsoft.Synchronization.Files, nic dalšího nebudeme prozatím potřebovat. Namespacy se stejným jménem přidáme k použití do zdrojových textů.
Jak bylo řečeno v předchozím díle, základem synchronizace jsou provideři. Pro synchronizaci obsahu adresářů zvolíme FileSyncProvider, který je již předpřipraven. Celý kód je skutečně velmi jednoduchý.
const string sourceDir = @"C:\SOURCE";
const string destDir = @"C:\DEST";
SyncId replicaId1 = new SyncId(new Guid(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1));
SyncId replicaId2 = new SyncId(new Guid(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2));
using (FileSyncProvider source = new FileSyncProvider(replicaId1, sourceDir, null, FileSyncOptions.None, sourceDir, "meta1.sync", Path.GetTempPath()),
dest = new FileSyncProvider(replicaId2, destDir, null, FileSyncOptions.None, destDir, "meta2.sync", Path.GetTempPath()))
{
SyncAgent agent = new SyncAgent();
agent.LocalProvider = source;
agent.RemoteProvider = dest;
agent.Direction = SyncDirection.Upload;
agent.Synchronize();
}
Nejprve si připravíme identifikace replik. Pro každý adresář jednu. ID musí být pokaždé stejné, ale můžete si udělat vlastní systém pro generování. Dokonce si můžete ID uložit přímo do synchronizovaného adresáře do souboru. Poté si již vytvoříme vlastní instance providerů. Předáme identifikace replik a název adresáře, což jsou hlavní parametry. Další jen heslovitě: FileSyncScopeFilter nepoužíváme, avšak vězte, že pomocí něj můžete upravit jaké soubory se (ne)budou synchronizovat, případně jaké adresáře budou ignorovány apod.; FileSyncOptions opět nepoužijeme, nicméně umožňuje nám doladit chování během synchronizace (např. mazání souborů do koše); následuje adresář pro umístění souboru s metadaty; jeho název; a cesta pro dočasné soubory. Poté vytvoříme agenta (SyncAgent), který celou synchronizaci provede (za použití providerů) a nastavíme, kdo jsou „domácí“ a kdo jsou „hosté“. Nakonec nastavíme směr (Upload; možno zvolit i obrácený [Download] či kombinace DownloadAndUpload resp. UploadAndDownload). Nezbývá než synchronizaci spustit posledním příkazem.
Spustíte-li aplikaci (a máte-li správně adresáře) během pár vteřin (podle velikosti položek) bude sesynchronizováno. Můžete si též všinout, že v adresářích vznikl nový soubor – meta1.sync v SOURCE a meta2.sync v DEST. Jedná se o zmiňované soubory metadat. Také je důležité si povšimnout, že tyto soubory nejsou synchronizovány (v DEST není meta1.sync). Velmi jednoduché, nemyslíte?
Agent (SyncAgent) má, mimo jiné, jednu zajímavou událost a sice SessionProgress. Díky této události můžete „sledovat“ či spíše informovat uživatele v jakém stavu se synchronizace nachází pomocí proměnných CompletedWork a TotalWork. Zajímavé události má však i provider. Jedná se o události AppliedChange resp. ApplyingChange a SkippedChange. První sada událostí nám umožňuje reagovat na změny, které se provádí během synchronizace. Obsluha může tedy vypadat takto (triviální příklad):
switch (e.ChangeType)
{
case ChangeType.Create:
Console.WriteLine("Done *create* action on file: {0}", e.NewFilePath);
break;
case ChangeType.Delete:
Console.WriteLine("Done *delete* action on file: {0}", e.OldFilePath);
break;
case ChangeType.Overwrite:
Console.WriteLine("Done *overwrite* action on file: {0}", e.NewFilePath);
break;
case ChangeType.Rename:
Console.WriteLine("Done *rename* action on file: {0} (OldName: {1})", e.NewFilePath, e.OldFilePath);
break;
}
Podobně je možné zpracovat událost SkippedChange, která nás informuje o přeskočení dané akce, včetně důvodu (např. na povel aplikace v obsluze ApplyingChange či kvůli nemožnosti přečíst soubor, …). Není tedy obtížné napsat si logování provádění a v případě problémů se podívat, co je příčinou problému.
Pokud je kopírovaný soubor velký, případně je přenášen po pomalém médiu, může se hodit událost CopyingFile, která vám umožní zobrazit aktuální procentuální stav práce nad daným souborem.
Poslední o čem se dnes zmíníme, jsou konflikty, které mohou vznikat. FileSyncProvider je prozatím velmi chytrý v tom, jak řešit problém. Kolize řeší sám podle definovaných pravidel, převedším tak, aby se nic neztratilo (mohou však vznikat fantomové položky). Pro přesný popis doporučuji prostudovat [1] sekce Conflict Handling. Za normálních okolností můžeme chování řídit pomocí Configuration.ConflictResolutionPolicy a definovat „kdo vyhraje“.
[1]
http://msdn2.microsoft.com/en-us/sync/bb887623.aspx