ShellBoost

Amalga Drive sample

The OnDemandSynchronizer class is still provided with ShellBoost but should not be used for new projects. New projects should use the MultiPointSynchronizer class coupled with the OnDemandLocalFileSystem class as explained in the Files On-Demand chapter.
This sample has not been ported to the new MultiPointSynchronizer and still uses the legacy OnDemandSynchronizer clas.

Source repository: https://github.com/aelyo-softworks/AmalgaDrive

A WPF application shell folder. Demonstrates the File On-Demand feature. The Visual Studio solution has 3 projects:

AmalgaDrive.DavServer: A zero-dependency custom WebDAV-compatible Server library that serves a local directory as a WebDAV directory resource. Written for .NET core 3.

AmalgaDrive.DavServerSite: A sample WebDAV web site. It’s merely a web host for the AmalgaDrive.DavServer library. Written with ASP.NET core 3.

AmalgaDrive: a WPF Shell Namespace Extension that amalgamates various Cloud drives. Written with .NET Framework.

Amalga Drive has been written to connect to implementations of the ShellBoost’s IRemoteFileSystem interface (described in the Files On-Demand support chapter). The sample currently contains only one implementation of IRemoteFileSystem which is an implementation that relies on a WebDAV server for the “remote” file system. The implementation is in the DavFileSystem.cs and DavResource.cs files. This DavFileSystem implementation has been written to connect to any WebDAV service, local, or on the internet. It has been successfully tested to work with AmalgaDrive.DavServerSite, www.box.com and www.cloudme.com WebDAV implementations.

Other implementation of IRemoteFileSystem could be added to enable Amalg aDrive to use other cloud “drive” systems (Google, Amazon, etc.).

AmalgaDrive.DavServerSite sample

AmalgaDrive.DavServerSite is not mandatory to run to test Amalga Drive since Amalga Drive supports by default other WebDAV services such as www.box.com or www.cloudme.com. if you want to test it, it has no UI, it’s an API-only site.

What it does is serve an existing folder on your hard disk as a WebDAV directory resource. The served folder can be configured in the appsettings.json file in the project. It looks like this:

{
  "Logging": {
    "IncludeScopes": false,
    "Debug": {
      "LogLevel": {
        "Default": "Warning"
      }
    },
    "Console": {
      "LogLevel": {
        "Default": "Warning"
      }
    }
  },
    "DavServer": {
    "FileSystem": {
      "TypeName": "AmalgaDrive.DavServer.FileSystem.Local.LocalFileSystem",
      "Properties": {
        "RootPath": "d:\\temp\\amalga", // TODO: change the path here to match your environment
        "DirectoryBrowserRequestPath": "/dav" // should match a/href in default.html and DavServerOptions.cs "BaseUrl" option
      }
    }
  }
}

Just change the RootPath value and restart the server to serve another folder on your disk.

By default, it runs on http://localhost:61786/dav when started from IIS Express and http://localhost:61787/dav when started from Kestrel.

Using Amalga Drive

When you start Amalga Drive, open the “File / Add a Cloud Drive…” menu item, then enter login information and press OK.

This is an example with the www.box.com service:

Using Amalga Drive - Picture 57

This is an example with the AmaldaDrive.DavServerSite sample (there is no authentication for demonstration purposes). Make sure the url corresponds to your configuration and to the Web Server used for testing (Kestrel vs IIS Express, etc. see chapter above)

Using Amalga Drive - Picture 71

Once you’ve added at least one Cloud Drive, you should see something like this. You can add any number of drives. Right now, remember that the program only supports WebDav-type cloud drives.

Using Amalga Drive - Picture 72

Synchronization should happen automatically in 300 seconds (by default). If you want to force synchronization, just press the green refresh button. Note there is a menu item in the Tools menu that allows you to see sync logs.

Let’s suppose you’re using a www.box.com account with the following files in your web personal storage:

Using Amalga Drive - Picture 66

If you want to see the drive like a standard Windows directory path, click on the Amalga Drive UI first orange button (tooltip says “Open Path”). You should see something like this in Windows Explorer:Using Amalga Drive - Picture 67

As you see it looks like OneDrive, with a Status column that represents the offline availability of each shell item. Nothing is stored locally yet, as the little blue cloud icon means “Available when online”. If you double-click on one file for example the AboutWindow.xaml.cs sample file, Windows will ask Amalga Drive to download the file, once downloaded (in the background, the process is completely transparent to the end-user), the file will open (with your configured editor for .cs files in this case). At the same time, the shell will automatically update the icon to a little green circle check that means “Available on this device”.

Using Amalga Drive - Picture 68

Note that for this to work, we don’t use any Shell Namespace Extension. But you can also view the same directory hierarchy using a ShellBoost Namespace Extension embedded into Amalga Drive. Click on the Amalga Drive UI second orange button (tooltip says “Open Extension”). You should see something like this in Windows Explorer:

Using Amalga Drive - Picture 3

As you see we have the same Status icon column in our namespace extension. The column is added to a folder with this code:

public OnDemandRootFolder(OnDemandShellFolderServer server, ShellItemIdList idList, DirectoryInfo info)
    : base(idList, info)
{
    if (server == null)
        throw new ArgumentNullException(nameof(server));
 
    if (info == null)
        throw new ArgumentNullException(nameof(info));
 
    Server = server;
 
    // since this is a FileSystem oriented NSE, we let base properties pass through
    ReadPropertiesFromShell = true;
 
    /// We just add the sync status column.
    AddColumn(Props.System.StorageProviderUIStatus, SHCOLSTATE.SHCOLSTATE_ONBYDEFAULT);
}

And each item declares its state like this:

public override bool TryGetPropertyValue(PropertyKey key, out object value)
{
    // this property is asked by the Shell to display the sync status icon
    if (key == Props.System.StorageProviderUIStatus)
    {
        value = GetSyncState(this);
        return true;
    }
    return base.TryGetPropertyValue(key, out value);
}
 
private static MemoryPropertyStore GetSyncState(ShellItem item)
{
    var ms = new MemoryPropertyStore();
    ms.SetValue(Props.System.PropList.StatusIcons, "prop:" + Props.System.StorageProviderState.CanonicalName);
    ms.SetValue(Props.System.PropList.StatusIconsDisplayFlag, (uint)2);
 
    // read the sync state from the shell
    // it works because we have set ReadPropertiesFromShell = true as a passthrough
    var state = item.GetPropertyValue(Props.System.StorageProviderState, 0);
    ms.SetValue(Props.System.StorageProviderState, state);
 
    return ms;
}