Creating WebDAV Server with Versioning Support
DeltaV Classes and Interfaces
DeltaV server provides the ability to check-out / check-in files and keeps versions track. To add versioning features, you must implement 3 additional interfaces: IVersionableItem, IVersion and IHistory. The class diagram below shows DeltaV interfaces that you will usually use to build DeltaV server. Interfaces specific to various server features are marked as Class 1, Class 2 and DeltaV:
Class 2 interfaces are optional for DeltaV server, if you do not need to support Class 2 clients (such as Web Folders on Windows 7, Windows Vista, Mac OS X, Microsoft Office, etc) you do not have to implement them. Class 2 interfaces will be also necessary if you would like to implement auto-versioning modes for versioning-unaware WebDAV clients.
Usually, you will implement IVersionableItem on your file items in addition to IFile and ILock interfaces. You will also provide 2 new item types – version and version history items. Your version items will implement IVersion and IContent interface representing a single file version. Version history item will contain all versions of an item. The class diagram below shows classes in your application supporting both Class 2 and DeltaV:
As with Class 1 and Class 2 servers, each item in your repository must have its own unique URL including versions and history items. Now your ContextAsync.GetHierarchyItemAsync must return 4 types of items: files, folders, versions and version history items.
Starting Versioning
Usually by default all items in the repository are not under version control. The item actually behaves like a Class 2 item. To start creating versions, DeltaV client application must first issue version-control command for an item. The engine will call IVersionableItem.PutUnderVersionControlAsync method passing true as a parameter. If you want versioning to start automatically without explicit request from the client you can set DavEngineAsync.AutoPutUnderVersionControl to true. In this case IVersionableItem.PutUnderVersionControlAsync will be called for non-version controlled items before the first item update.
In your IVersionableItem.PutUnderVersionControlAsync implementation you must create a new version. You will copy content and properties from the item to newly created version and save the new version in your repository. After the call to PutUnderVersionControlAsync, the item must have 1 version in its versions list and IVersionableItem.VersionHistory must return object implementing IHistory interface that contains a single version. IHistory.GetCurrentVersionAsync must point to the new version.
Updating Item Content and Properties
To start updating item, the client application must check-out the item. In your IVersionableItem.CheckOutAsync implementation you will mark the item as checked-out and allow item modifications. When item is in check-out state WebDAV client can issue commands updating item contents and properties. During the updates, engine will call IContent.WriteAsync and IHierarchyItem.UpdatePropertiesAsync.
You should not create any new versions during IVersionableItem.CheckOutAsync call or during the updates. Instead, you will create a new version during IVersionableItem.CheckInAsync call.
When client finishes item updates it will check-in item or rollback modifications issuing uncheck-out command. During the IVersionableItem.CheckInAsync call, you must create a new version copying content and properties from modified item to a new version. IHistory.GetCurrentVersionAsync must point to the newly created version.
If client issues uncheck-out command you must restore the pre-check-out stare of the item. In this case during IVersionableItem.UnCheckOutAsync call you will copy content and properties from the latest version to the item. During the IVersionableItem.UnCheckOutAsync call item must be marked as checked-in.
Here is the typical versioning workflow:
- Engine calls PutUnderVersionControlAsync. Your implementation must create a new version, copy content and properties from this item to a new version.
- Engine calls CheckOutAsync. Your code marks the item as checked-out.
- Engine calls SaveFromStream or UpdatePropertiesAsync. Your code modifies item content and properties.
- Engine calls CheckInAsync or UnCheckOutAsync. For CheckInAsync - your code creates a new version, copies content and properties from this item to a new version. For UnCheckOutAsync - copies content and properties from the current version to this item. Marks item as checked-in.
Stopping Versioning
Each object that implements IHistory interface must have its own unique URL returned by Path property. If the DeltaV client application decides to turn-off versioning it will submit delete request to this URL. Engine will call IVersionableItem.PutUnderVersionControlAsync method passing false as a parameter. In your implementation, you will delete all versions. IVersionableItem.VersionHistory property must return null after this call.
Auto-versioning Modes
Auto-versioning provides backward compatibility with WebDAV clients that do not support DeltaV features (versioning-unaware WebDAV clients). If your item is being version-controlled and WebDAV client is trying to modify a checked-in item auto-versioning may automatically check-out the item and then check-in creating a new item version. To reduce number of versions created by versioning-unaware clients DeltaV standard and IT Hit WebDAV Server Engine provides several auto-versioning modes. The engine reads the mode from IVersionableItem.GetAutoVersionAsync method before the update. You can find a description of each mode here. Note that all auto-versioning logics apply only to checked-in items. If you item is in checked-out state and your server permissions allow the user to modify the item the client application will be able to update items content and properties.
We will describe CheckOutUnlockedCheckIn mode that provides balance between number of versions created and support for versioning-unaware clients. In this mode lock and unlock commands function as check-in and check-out respectively. On the other hand, Class 1 + DeltaV client applications without lock support can still update items and create versions.
When the update request issued, the item is being automatically checked-out by the engine. First the engine calls IVersionableItem.CheckOutAsync method passing IsAutoCheckOut parameter set to true. You must save the value passed into CheckOutAsync method in your storage, and return it when IVersionableItem.IsAutoCheckedOut is called. Then engine calls item update methods such as IFile.WriteAsync and/or IHierarchyItem.UpdatePropertiesAsync. After the update, engine checks-in the item if it was not locked.
If the item was locked, during the unlock request engine first reads IsAutoCheckedOut property and calls IVersionableItem.CheckInAsync if IsAutoCheckedOut is true. Finally engine calls ILock.UnlockAsync.
CheckOutUnlockedCheckIn mode workflow:
- Modification request:
- Engine calls IVersionableItem.CheckOutAsync.
- Engine calls IFile.WriteAsync or IHierarchyItem.UpdatePropertiesAsync.
- Engine calls IVersionableItem.CheckInAsync if item is not locked.
- Unlock request:
- Engine reads IVersionableItem.IsAutoCheckedOut property.
- Engine calls IVersionableItem.CheckInAsync if IVersionableItem.IsAutoCheckedOut is true.
- Engine calls ILock.UnlockAsync.
Below you can see the how other 3 auto-versioning modes comparing to CheckOutUnlockedCheckIn mode: