Detecting Changes Using Content and Metadata eTags (Versions)
The functionality described in this section is provided in v8.1 Beta 2 and later versions.
Starting with v8.1 the Engine detects changes in file content and metadata using eTag fields (versions in terms of iOS and macOS) provided in metadata object.
The metadata interfaces provide two separate fields for detecting changes in metadata and in content: IFileSystemItemMetadata.MetadataETag property and IFileMetadata.ContentETag. These fields allow updating file properties (for example locks) without updating file content.
Here is the typical eTag lifecycle:
- You will store your content eTag and metadata eTag in your remote storage. Your remote storage code will update each eTag on every file content change and every metadata change. You will return eTags with each item when listing folder content and creating new items. You will also return eTags when listing changes if you have Sync ID algorithm implemented.
- When feeding data to the Engine in IFolder.GetChildrenAsync(), IFolder.CreateFileAsync(), IFile.ReadAsync() and other methods as well as you will set IFileSystemItem.MetadataETag and IFileMetadata.ContentETag fields to values returned from your remote storage. The Engine will store eTags with each item.
- When you call IServerNotifications.UpdateAsync() you will set MetadataETag and ContentETag fields in your metadata object. The Engine will compare new eTags with eTags stored with the item. It will update metadata and content only if eTags do not match.
To avoid unnecessary item updates never set the IFileSystemItemMetadata.MetadataETag and IFileMetadata.ContentETag properties to null value.
Here is how your IFolder.CreateFileAsync() method will typically look like in v8.1 and later version:
public async Task<IFileMetadata> CreateFileAsync( IFileMetadata fileMetadata, Stream content = null, ...) { // Create file in your remote storage here and return // the newly created file remote storage item ID, // content eTag and metadata eTag to the Engine. var res = Serv.Create(RemoteStoragePath, content); return new FileMetadataExt() { RemoteStorageItemId = res.RemoteStorageId, ContentETag = res.ContentETag, MetadataETag = res.MetadataETag, ... }; }
Inside other methods, typically in IFile.WriteAsync() you will read the ContentETag and send it to the remote storage as part of the update. This is to avoid content to be overwritten, in case your remote storage content changed and the item was not locked:
public async Task<IFileMetadata> WriteAsync( IFileSystemBasicInfo fileBasicInfo, Stream content = null ...) { string oldContentEtag = fileBasicInfo.ContentETag; // Update remote storage file content and get a new content eTag. var res = Serv.Upload(RemoteStoragePath, content, oldContentEtag); return new FileMetadataExt() { ContentETag = var.ContentEtag, MetadataETag = var.MetadataEtag ... }; }
On Windows platform, when developing and debugging you can read eTags using ICustomData.GetMetadataETag() and ICustomData.GetContentETag() extension methods. For example you can show them in custom columns in Windows Explorer, so you can see eTags changes.
Note that if your IFileSystemItemMetadata.MetadataETag field is null, the Engine will be unable to detest changes, and as such, will always update metadata on every item update. The same thing with the content eTag. If IFileMetadata.ContentETag is null, the Engine will re-download content on every file update.