Creating Virtual Drive in .NET

In this article

Creating Virtual Drive in .NET

In this article, we describe advanced features such as move operation, items locking and transactional save. 

Locking 

Documents Locking

To lock items, the IT Hit User File System provides the ILock interface. You will implement it on files and folders that support locking. This interface provides LockAsync(), UnlockAsync() and GetLockModeAsync() methods.

Inside your ILock.LockAsync() method implementation you will lock the file in your remote storage as well as you will save the LockMode, passed as a parameter, somewhere in your local storage, on the client machine:

public async Task LockAsync(LockMode lockMode, IOperationContext operationContext=null)
{
    Logger.LogMessage($"{nameof(ILock)}.{nameof(LockAsync)}()", UserFileSystemPath);

    ExternalDataManager cdm = Engine.CustomDataManager(UserFileSystemPath, Logger);
    LockManager lockManager = cdm.LockManager;
    if (!await lockManager.IsLockedAsync()
        && !Engine.CustomDataManager(UserFileSystemPath).IsNew)
    {
        // Set pending icon, so the user has feedback as lock operation may
        // take some time.
        await cdm.SetLockPendingIconAsync(true);

        // Call your remote storage here to lock the item.
        // Save the lock token and other lock info received from the remote 
        // storage on the client. Supply the lock-token as part of each remote 
        // storage update in the IFile.WriteAsync() method.

        LockInfo lockInfo = await Program.DavClient.LockAsync(
            new Uri(RemoteStoragePath), 
            LockScope.Exclusive, false, 
            null, 
            TimeSpan.MaxValue);
        ServerLockInfo serverLockInfo = new ServerLockInfo
            {
                LockToken = lockInfo.LockToken.LockToken,
                Exclusive = lockInfo.LockScope == LockScope.Exclusive,
                Owner = lockInfo.Owner,
                LockExpirationDateUtc = DateTimeOffset.Now.Add(lockInfo.TimeOut)
            };

        // Save lock-token and lock-mode.
        await lockManager.SetLockInfoAsync(serverLockInfo);
        await lockManager.SetLockModeAsync(lockMode);

        // Set lock icon and lock info in custom columns.
        await cdm.SetLockInfoAsync(serverLockInfo);

        Logger.LogMessage("Locked in remote storage succesefully.", UserFileSystemPath);
    }
}

In your ILock.UnlockAsync() method you will unlock the item in your remote storage:

public async Task UnlockAsync(IOperationContext operationContext=null)
{
    ExternalDataManager cdm = Engine.CustomDataManager(UserFileSystemPath, Logger);
    LockManager lockManager = cdm.LockManager;

    // Set pending icon, so the user has a feedback as unlock operation may 
    // take some time.
    await cdm.SetLockPendingIconAsync(true);

    // Read lock-token from lock-info file.
    string lockToken = (await lockManager.GetLockInfoAsync()).LockToken;
    LockUriTokenPair[] lockTokens = new LockUriTokenPair[] 
        { 
            new LockUriTokenPair(new Uri(RemoteStoragePath),
            lockToken)
        };

    // Unlock the item in the remote storage.
    try
    {
        await Program.DavClient.UnlockAsync(new Uri(RemoteStoragePath), lockTokens);
    }
    catch (ITHit.WebDAV.Client.Exceptions.ConflictException)
    {
        // The item is already unlocked.
    }

    // Delete lock-mode and lock-token info.
    lockManager.DeleteLock();

    // Remove lock icon and lock info in custom columns.
    await cdm.SetLockInfoAsync(null);

    Logger.LogMessage("Unlocked in the remote storage succesefully", UserFileSystemPath);
}

 

Inside your ILock.GetLockModeAsync() you will return your stored LockMode to the Engine:

public async Task<LockMode> GetLockModeAsync(IOperationContext operationContext=null)
{
    LockManager lm = Engine.CustomDataManager(UserFileSystemPath, Logger).LockManager;
    return await lm.GetLockModeAsync();
}

Storing the LockMode

During the ILock.LockAsync() call you must store the LockMode passed to this method on your local machine. When the file handle is closed the Engine will request the LockMode by calling your ILock.GetLockModeAsync() method implementation. You will typically return the LockMode passed into LockAsync() from this method. If your GetLockModeAsync() method returns LockMode.Auto, the Engine will unlock the file by calling the ILock. UnlockAsync() method.

Do NOT store the LockMode in your remote storage, as the ILock. GetLockModeAsync() method may be called from the Windows Explorer context menu and it expects a fast response in this case.

Manual Locking

To lock or unlock the document on the client machine, for example from your custom Windows Explorer lock context menu command, you will call methods of the IClientNotifications interface which is returned by the IEngine.ClientNotifications() call:

IClientNotifications cn = engine.ClientNotifications("C:\\Users\\User1\VD\\myfile.ext");
cn.LockAsync(LockMode.Manual);

The IClientNotifications.LockAsync() method has a parameter that indicates if the document should be automatically unlocked when the file handle is closed. This parameter will be passed to your ILock.LockAsync() method implementation. Typically you will pass the LockMode. Manual parameter to IClientNotifications.LockAsync() call, which will indicate that you will unlock the document manually, by calling the IClientNotifications.UnlockAsync() method. If you pass the LockMode.Auto, the file will be unlocked by calling ILock.UnlockAsync() when the file handle is closed.

Automatic Locking

On the Windows platform, the IT Hit User File System supports automatic documents locking/unlocking. Typically automatic document locking is useful to automatically lock the document when it is opened by Microsoft Office and unlock on close.

To enable the automatic documents locking set the EngineWindows.AutoLock property to true when creating the Engine instance.

If the automatic documents locking is enabled, when a file handle is opened with the FILE_SHARE_READ or FILE_SHARE_DELETE or FILE_SHARE_NONE sharing mode, the Engine will call the ILock. LockAsync() method passing LockMode.Auto. When the file handle is closed it will call ILock. UnlockAsync() method.

Locking Events Design

Note that the locking event occurs after the file is being opened for writing. The failed locking event can NOT prevent the file from being opened for editing. This is because the Engine and underlying platform API do not provide any events that occur during the file open. The reason behind such a design is that file opening operation is a frequent event and must be instant, while any requests to the remote storage will slow down the file system performance. In addition to that, your file system may be in offline mode, with a server being unavailable and unable to lock the file.

In case your file failed to lock, either because it is being locked by another user, or because of any other resons, you can mark the file as read-only, so it can NOT be saved. While the read-only attribute does NOT protect the file from modifications, still most applications, including Microsoft Office, will respect the read-only attribute and will NOT update the file.

Another option is to notify clients via web sockets (or another channel) and set the read-only flag on the file as well as render the lock icon in Windows Explorer on the client machines when the file is locked on the server.

Open and Close Events

The Engine provides the IFile.OpenAsync() and the IFile.CloseAsync() methods, that are called when the file handle is being opened and closed. Note that both events occur after the file is opened/closed and you can not prevent a file handle from being opened or closed. 

For performance reasons, neither the Engine nor the underlying platform provides events that occur before the file handle open or close events or any events that can prevent the file from opening/losing.    

 

Next Article:

Previous Versions