Custom File System Provider

The Bootstrap File Manager allows you to implement custom file system provider. A custom provider should expand the FileSystemProviderBase class or one of its ancestors (demonstrated in the File System Providers demo). You can override the following virtual methods to provide the custom logic:

A custom provider can be assigned to Bootstrap File Manager control using the CustomFileSystemProvider or CustomFileSystemProviderTypeName property. The ProviderType property needs to be set to Custom or NotSet when a custom provider is used.

The custom file system provider in this demo (the SortingFileSystemProvider class) extends the sorting capabilities of the PhysicalFileSystemProvider class. By default, the File Manager sorts files and folders by their names in ascending order. The custom provider allows sorting by other properties of the FileManagerFile and FileManagerFolder classes in ascending or descending order.

Sort By:
<div class="d-flex my-4">
    <div class="mr-4 my-auto align-baseline"><b>Sort By:</b></div>
    <dx:BootstrapToolbar runat="server" OnItemClick="Item_Click" AutoPostBack="true">
        <Items>
            <dx:BootstrapToolbarItem Text="Name" Name="Name" GroupName="SortProperty" Checked="true" BeginGroup="true"></dx:BootstrapToolbarItem>
            <dx:BootstrapToolbarItem Text="Date Modified" Name="LastWriteTime" GroupName="SortProperty"></dx:BootstrapToolbarItem>
            <dx:BootstrapToolbarItem Text="Size" Name="Length" GroupName="SortProperty"></dx:BootstrapToolbarItem>
            <dx:BootstrapToolbarItem Text="Ascending" Name="ASC" GroupName="SortOrder" Checked="true" BeginGroup="true"></dx:BootstrapToolbarItem>
            <dx:BootstrapToolbarItem Text="Descending" Name="DSC" GroupName="SortOrder"></dx:BootstrapToolbarItem>
        </Items>
    </dx:BootstrapToolbar>
</div>
<dx:BootstrapFileManager runat="server" ID="FileManagerCustomProvider" CustomFileSystemProviderTypeName="SortingFileSystemProvider" Height="500px">
    <Settings RootFolder="~/Content/FileManager/Files" ThumbnailFolder="~/Content/FileManager/Thumbnails" />
    <SettingsFolders Visible="false" />
    <SettingsBreadcrumbs Visible="true" />
    <SettingsFileList ShowFolders="true">
    </SettingsFileList>
    
</dx:BootstrapFileManager>
protected void Page_Load(object sender, EventArgs e) {
    if(!IsPostBack)
        Session["FileManagerSortOptions"] = new FileManagerSortOptions();
}
protected void Item_Click(object sender, BootstrapToolbarItemEventArgs e) {
    FileManagerSortOptions options = (FileManagerSortOptions)Session["FileManagerSortOptions"];
    switch(e.Item.GroupName) {
        case "SortProperty":
            options.ItemProperty = e.Item.Name;
            FileManagerCustomProvider.Refresh();
            break;
        case "SortOrder":
            options.IsAscendingOrder = e.Item.Name.Equals("ASC");
            FileManagerCustomProvider.Refresh();
            break;
        default:
            break;
    }
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Web;
using System.Web.Hosting;
using DevExpress.Web;
public class FileManagerSortOptions {
    public FileManagerSortOptions() {
        ItemProperty = "Name";
        IsAscendingOrder = true;
    }
    public string ItemProperty { get; set; }
    public bool IsAscendingOrder { get; set; }
}
public class SortingFileSystemProvider : PhysicalFileSystemProvider {
    public SortingFileSystemProvider(string rootFolder)
        : base(rootFolder) {
    }
    protected FileManagerSortOptions SortOptions {
        get {
            var options = HttpContext.Current.Session["FileManagerSortOptions"];
            return options != null ? (FileManagerSortOptions)options : new FileManagerSortOptions();
        }
    }
    public override IEnumerable<FileManagerFile> GetFiles(FileManagerFolder folder) {
        return GetSortedItems(base.GetFiles(folder));
    }
    public override IEnumerable<FileManagerFolder> GetFolders(FileManagerFolder parentFolder) {
        IEnumerable<FileManagerFolder> folders = base.GetFolders(parentFolder);
        Func<FileManagerFolder, object> sortExpression = null;
        if(SortOptions.ItemProperty.Equals("Length"))
            sortExpression = folder => GetFolderSize(folder);
        return GetSortedItems(folders, sortExpression);
    }
    IEnumerable<T> GetSortedItems<T>(IEnumerable<T> items, Func<T, object> sortExpression = null) {
        if(sortExpression == null)
            sortExpression = GetSortByItemPropertyExpression<T>(SortOptions.ItemProperty);
        return SortOptions.IsAscendingOrder ? items.OrderBy(sortExpression) : items.OrderByDescending(sortExpression);
    }
    Func<T, object> GetSortByItemPropertyExpression<T>(string propertyName) {
        var item = Expression.Parameter(typeof(T), "item");
        var prop = Expression.Property(item, propertyName);
        return Expression.Lambda<Func<T, object>>(Expression.Convert(prop, typeof(object)), item).Compile();
    }
    long GetFolderSize(FileManagerFolder folder) {
        DirectoryInfo directoryInfo = new DirectoryInfo(HostingEnvironment.MapPath(folder.FullName));
        FileInfo[] filesInfo = directoryInfo.GetFiles("*", SearchOption.AllDirectories);
        long folderSize = 0;
        foreach(FileInfo info in filesInfo)
            folderSize += info.Length;
        return folderSize;
    }
}

Custom Toolbar

You can add custom items to the Bootstrap File Manager’s toolbar and context menu. These custom items are objects of the BootstrapFileManagerToolbarCustomButton and BootstrapFileManagerToolbarCustomDropDownButton types respectively.

The File Manager control provides the following API related to custom buttons:

In this demo, the File Manager toolbar is extended with three custom items:

  • Two of these items allow you to switch between the Thumbnails and Details view modes.
  • The third one invokes a popup displaying a file’s or folder’s properties. The same item is also added to the context menu.
<dx:BootstrapFileManager runat="server" ID="FileManagerCustomToolbar" Height="500px" OnLoad="FileManagerCustomToolbar_Load" OnCustomCallback="FileManagerCustomToolbar_CustomCallback"
    CustomFileSystemProviderTypeName="MetadataFileSystemProvider" Settings-EnableClientSideItemMetadata="true">
    <SettingsToolbar ShowPath="false">
        <Items>
            <dx:BootstrapFileManagerToolbarCustomButton CommandName="Properties" CssClass="btn-properties" IconCssClass="fas fa-info-circle" ToolTip="Shows the properties for the selected item" />
            <dx:BootstrapFileManagerToolbarRefreshButton BeginGroup="true" />
            <dx:BootstrapFileManagerToolbarCustomButton BeginGroup="true" GroupName="ViewModes" IconCssClass="fas fa-th-large" Tooltip="Thumbnails" CommandName="Thumbnails" AdaptivePriority="1" AdaptiveText="Thumbnails" />
            <dx:BootstrapFileManagerToolbarCustomButton GroupName="ViewModes" IconCssClass="fas fa-table" Tooltip="Details" CommandName="Details" AdaptivePriority="1"  AdaptiveText="Details" />
            <dx:BootstrapFileManagerToolbarFilterBox Caption="" NullText="Search..." />
        </Items>
    </SettingsToolbar>
    <SettingsContextMenu>
        <Items>
            <dx:BootstrapFileManagerToolbarRefreshButton />
            <dx:BootstrapFileManagerToolbarCustomButton CommandName="Properties" Text="Properties" IconCssClass="fas fa-info-circle" ToolTip="Shows the properties for the selected item" />
        </Items>
    </SettingsContextMenu>
    <ClientSideEvents CustomCommand="onCustomToolbarCommand" ToolbarUpdating="onToolbarUpdating" SelectionChanged="onSelectionChanged" />
    <SettingsFileList ShowFolders="true">
    </SettingsFileList>
    <Settings RootFolder="~/Content/FileManager/Files" ThumbnailFolder="~/Content/FileManager/Thumbnails" />
</dx:BootstrapFileManager>
<dx:BootstrapPopupControl runat="server" ClientInstanceName="propertiesPopup" PopupAnimationType="Fade" CloseAnimationType="Fade"
    HeaderText="Properties" PopupVerticalAlign="Below" PopupVerticalOffset="4" AllowDragging="true" DragElement="Header" CloseOnEscape="true" Width="320px">
    <CssClasses Content="small" Header="bg-secondary text-white py-2" CloseButton="text-white" />
    <SettingsBootstrap Sizing="Small" />
</dx:BootstrapPopupControl>
FileListView ViewMode {
    get {
        var view = Session["FileManagerViewMode"];
        return view == null ? FileListView.Thumbnails : (FileListView)Session["FileManagerViewMode"];
    }
    set {
        FileManagerCustomToolbar.SettingsFileList.View = value;
        Session["FileManagerViewMode"] = value;
    }
}
protected void FileManagerCustomToolbar_Load(object sender, EventArgs e) {
    if(FileManagerCustomToolbar.IsCallback)
        System.Threading.Thread.Sleep(1000);
    FileManagerCustomToolbar.SettingsFileList.View = ViewMode;
    bool isDetailsView = ViewMode.Equals(FileListView.Details);
    ((BootstrapFileManagerToolbarCustomButton)FileManagerCustomToolbar.SettingsToolbar.Items.FindByCommandName("Thumbnails")).Checked = !isDetailsView;
    ((BootstrapFileManagerToolbarCustomButton)FileManagerCustomToolbar.SettingsToolbar.Items.FindByCommandName("Details")).Checked = isDetailsView;
}
protected void FileManagerCustomToolbar_CustomCallback(object sender, DevExpress.Web.CallbackEventArgsBase e) {
    ViewMode = (FileListView)Enum.Parse(typeof(FileListView), e.Parameter.ToString());
}
function onToolbarUpdating(s, e) {
    var contextMenuItem = s.GetContextMenuItemByCommandName("Properties");
    contextMenuItem.SetVisible(e.activeAreaName == "Files");
    var enabled = s.GetSelectedItems().length > 0 && e.activeAreaName != "None";
    contextMenuItem.SetEnabled(enabled);
    s.GetToolbarItemByCommandName("Properties").SetEnabled(enabled);
}
function onCustomToolbarCommand(s, e) {
    switch(e.commandName) {
        case "Thumbnails":
        case "Details":
            s.PerformCallback(e.commandName);
            break;
        case "Properties":
            propertiesPopup.ShowAtElement($(s.GetMainElement()).find(".btn-properties")[0]);
            break;
    }
}
function onSelectionChanged(s, e) {
    var propertiesText = "";
    var selectedItems = s.GetSelectedItems();
    if(selectedItems[0] != null)
        updatePropertiesPopupContent(selectedItems[0].GetMetadata());
}
function updatePropertiesPopupContent(metadata) {
    var contentHtml = "";
    for(var key in metadata) {
        if(!metadata.hasOwnProperty) continue;
        var value = metadata[key];
        if(value)
            contentHtml += "<p>" + key + ": " + value + "</p>" + "\r\n";
    }
    propertiesPopup.SetContentHtml(contentHtml);
}
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using DevExpress.Web;
public class MetadataFileSystemProvider : PhysicalFileSystemProvider {
    public MetadataFileSystemProvider(string rootFolder)
        : base(rootFolder) {
    }
    protected internal virtual string MapPath(string virtualPath) {
        return System.Web.Hosting.HostingEnvironment.MapPath(virtualPath);
    }
    Dictionary<string, string> ExtensionsDisplayName {
        get {
            return new Dictionary<string, string>() {
                { ".txt", "Text Document (.txt)" },
                { ".rtf", "Rich Text Format (.rtf)" },
                { ".xml", "XML Document (.xml)" },
                { ".zip", "Compressed (zipped) Folder (.zip)" }
            };
        }
    }
    public override IEnumerable<FileManagerFile> GetFiles(FileManagerFolder folder) {
        List<FileManagerFile> result = new List<FileManagerFile>();
        foreach(FileManagerFile file in base.GetFiles(folder)) {
            var fileInfo = new FileInfo(MapPath(file.FullName));
            FileManagerFileProperties fileProperties = new FileManagerFileProperties() {
                Metadata = new Dictionary<string, object>()
            };
            FileVersionInfo myFileVersionInfo = FileVersionInfo.GetVersionInfo(MapPath(file.FullName));
            var version = myFileVersionInfo.FileVersion;
            string description = myFileVersionInfo.FileDescription;
            fileProperties.Metadata.Add("Name", file.Name);
            fileProperties.Metadata.Add("Type", ExtensionsDisplayName.ContainsKey(file.Extension) ? ExtensionsDisplayName[file.Extension]
                : string.Format("{0} File ({1})", file.Extension.Replace(".", "").ToUpper(), file.Extension));
            fileProperties.Metadata.Add("Size", fileInfo.Length.ToString("#,#") + " bytes");
            fileProperties.Metadata.Add("Created", fileInfo.CreationTime.ToString("U"));
            fileProperties.Metadata.Add("Modified", fileInfo.LastWriteTime.ToString("U"));
            fileProperties.Metadata.Add("Accessed", fileInfo.LastAccessTime.ToString("U"));
            fileProperties.Metadata.Add("Attributes", fileInfo.Attributes);
            fileProperties.Metadata.Add("Description", description);
            result.Add(new FileManagerFile(this, folder, file.Name, file.Id, fileProperties));
        }
        return result;
    }
    public override IEnumerable<FileManagerFolder> GetFolders(FileManagerFolder parentFolder) {
        List<FileManagerFolder> result = new List<FileManagerFolder>();
        foreach(FileManagerFolder folder in base.GetFolders(parentFolder)) {
            var folderInfo = new FileInfo(MapPath(folder.FullName));
            FileManagerFolderProperties folderProperties = new FileManagerFolderProperties() {
                Metadata = new Dictionary<string, object>()
            };
            var folderSecurity = File.GetAccessControl(MapPath(folder.FullName));
            folderProperties.Metadata.Add("Name", folder.Name);
            folderProperties.Metadata.Add("Type", "Folder");
            var directoryInfo = new DirectoryInfo(MapPath(folder.FullName));
            var filesInfo = directoryInfo.GetFiles("*", SearchOption.AllDirectories);
            long folderSize = 0;
            foreach (var info in filesInfo)
                folderSize += info.Length;
            var filesCount = filesInfo.Length;
            var subDirectoriesCount = directoryInfo.GetDirectories("*", SearchOption.AllDirectories).Length;
            folderProperties.Metadata.Add("Size", folderSize.ToString("#,#") + " bytes");
            folderProperties.Metadata.Add("Contains", string.Format("Files: {0}, Folders: {1}", filesCount, subDirectoriesCount));
            folderProperties.Metadata.Add("Created", folderInfo.CreationTime.ToString("U"));
            folderProperties.Metadata.Add("Modified", folderInfo.LastWriteTime.ToString("U"));
            folderProperties.Metadata.Add("Accessed", folderInfo.LastAccessTime.ToString("U"));
            folderProperties.Metadata.Add("Attributes", folderInfo.Attributes);
            result.Add(new FileManagerFolder(this, parentFolder, folder.Name, folder.Id, folderProperties));
        }
        return result;
    }
}

Custom Thumbnails

You can provide custom file thumbnails by handling the CustomThumbnail server event. In the the event handler, you can access information about the currently processed item using the BootstrapFileManagerThumbnailCreateEventArgs.Item property. Based on this information, you can then assign a custom thumbnail using the the BootstrapFileManagerThumbnailCreateEventArgs.ThumbnailIconCssClass or ThumbnailImage property.

<dx:BootstrapFileManager runat="server" ID="FileManagerCustomThumbnails" OnCustomThumbnail="FileManagerCustomThumbnails_CustomThumbnail" Height="640px">
    <Settings RootFolder="~/Content/FileManager/Files" InitialFolder="Music" ThumbnailFolder="~/Content/FileManager/Thumbnails" />
</dx:BootstrapFileManager>
protected void FileManagerCustomThumbnails_CustomThumbnail(object source, DevExpress.Web.Bootstrap.BootstrapFileManagerThumbnailCreateEventArgs e) {
    switch(((FileManagerFile)e.Item).Extension) {
        case ".avi":
            e.ThumbnailIconCssClass = "far fa-file-video";
            break;
        case ".zip":
            e.ThumbnailIconCssClass = "far fa-file-archive";
            break;
        case ".mp3":
            e.ThumbnailIconCssClass = "far fa-file-audio";
            break;
        case ".xml":
            e.ThumbnailIconCssClass = "far fa-file-code";
            break;
        case ".rtf":
            e.ThumbnailIconCssClass = "far fa-file-word";
            break;
        case ".txt":
            e.ThumbnailIconCssClass = "far fa-file-alt";
            break;
    }
}

Custom Columns

When used in Details view mode, the Bootstrap File Manager control can display custom columns. You can define custom column using the SettingsFileList.DetailsViewSettings.Columns collection property. Each custom column in this collection is a BootstrapFileManagerDetailsCustomColumn object.

File Manager control provides the following API related to custom columns:

This demo demonstrates how to implement custom header filter for such column. A custom file provider is implemented to save additional required metadata to the File Manager’s items based on the available file information. The custom column is then bound to the Type metadata field using the ItemMetadataKey property.

The custom header filter items are specified in the DetailsViewCustomColumnHeaderFilterFillItems server-side event handler. Filtering is performed using filter expressions based on the Criteria Language Syntax.

Documents
10/23/2019 10:33:43 AMFolderFolder
Images
10/23/2019 10:33:55 AMFolderFolder
Music
10/23/2019 10:33:55 AMFolderFolder
System
10/23/2019 10:33:55 AMFolderFolder
Video
10/23/2019 10:33:55 AMFolderFolder
Description.rtf
10/23/2019 5:43:14 AMRich Text Format (.rtf)1 B
Description.txt
10/23/2019 5:43:14 AMText Document (.txt)1 B
<dx:BootstrapFileManager runat="server" ID="FileManagerCustomColumns" OnDetailsViewCustomColumnHeaderFilterFillItems="FileManagerCustomColumns_DetailsViewCustomColumnHeaderFilterFillItems"
    CustomFileSystemProviderTypeName="MetadataFileSystemProvider" Height="480px">
    <Settings RootFolder="~/Content/FileManager/Files" ThumbnailFolder="~/Content/FileManager/Thumbnails" />
    <SettingsFileList View="Details" ShowFolders="true">
        <DetailsViewSettings>
            <Columns>
                <dx:BootstrapFileManagerDetailsColumn FileInfoType="Thumbnail" AdaptivePriority="2" />
                <dx:BootstrapFileManagerDetailsColumn FileInfoType="FileName" AdaptivePriority="1" />
                <dx:BootstrapFileManagerDetailsColumn FileInfoType="LastWriteTime" AdaptivePriority="2" />
                <dx:BootstrapFileManagerDetailsCustomColumn Caption="Type" Name="Type" ItemMetadataKey="Type"
                    ShowHeaderFilterButton="True" AllowSort="True" AllowTextTruncationInAdaptiveMode="true" />
                <dx:BootstrapFileManagerDetailsColumn FileInfoType="Size" AdaptivePriority="2" />
            </Columns>
        </DetailsViewSettings>
    </SettingsFileList>
</dx:BootstrapFileManager>
protected void FileManagerCustomColumns_DetailsViewCustomColumnHeaderFilterFillItems(object source, DevExpress.Web.Bootstrap.BootstrapFileManagerDetailsViewCustomColumnHeaderFilterFillItemsEventArgs e) {
    if(e.Column.Name.Equals("Type")) {
        e.Values.Clear();
        e.AddShowAll();
        e.AddValue("Folders", string.Empty, "Type In ('Folder','Compressed (zipped) Folder (.zip)')");
        e.AddValue("Documents", string.Empty, "Type In ('Text Document (.txt)','Rich Text Format (.rtf)','XML Document (.xml)')");
        e.AddValue("Images", string.Empty, "Type In ('JPG File (.jpg)','PNG File (.png)')");
        e.AddValue("Media Files", string.Empty, "Type In ('AVI File (.avi)','MP3 File (.mp3)')");
    }
}
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using DevExpress.Web;
public class MetadataFileSystemProvider : PhysicalFileSystemProvider {
    public MetadataFileSystemProvider(string rootFolder)
        : base(rootFolder) {
    }
    protected internal virtual string MapPath(string virtualPath) {
        return System.Web.Hosting.HostingEnvironment.MapPath(virtualPath);
    }
    Dictionary<string, string> ExtensionsDisplayName {
        get {
            return new Dictionary<string, string>() {
                { ".txt", "Text Document (.txt)" },
                { ".rtf", "Rich Text Format (.rtf)" },
                { ".xml", "XML Document (.xml)" },
                { ".zip", "Compressed (zipped) Folder (.zip)" }
            };
        }
    }
    public override IEnumerable<FileManagerFile> GetFiles(FileManagerFolder folder) {
        List<FileManagerFile> result = new List<FileManagerFile>();
        foreach(FileManagerFile file in base.GetFiles(folder)) {
            var fileInfo = new FileInfo(MapPath(file.FullName));
            FileManagerFileProperties fileProperties = new FileManagerFileProperties() {
                Metadata = new Dictionary<string, object>()
            };
            FileVersionInfo myFileVersionInfo = FileVersionInfo.GetVersionInfo(MapPath(file.FullName));
            var version = myFileVersionInfo.FileVersion;
            string description = myFileVersionInfo.FileDescription;
            fileProperties.Metadata.Add("Name", file.Name);
            fileProperties.Metadata.Add("Type", ExtensionsDisplayName.ContainsKey(file.Extension) ? ExtensionsDisplayName[file.Extension]
                : string.Format("{0} File ({1})", file.Extension.Replace(".", "").ToUpper(), file.Extension));
            fileProperties.Metadata.Add("Size", fileInfo.Length.ToString("#,#") + " bytes");
            fileProperties.Metadata.Add("Created", fileInfo.CreationTime.ToString("U"));
            fileProperties.Metadata.Add("Modified", fileInfo.LastWriteTime.ToString("U"));
            fileProperties.Metadata.Add("Accessed", fileInfo.LastAccessTime.ToString("U"));
            fileProperties.Metadata.Add("Attributes", fileInfo.Attributes);
            fileProperties.Metadata.Add("Description", description);
            result.Add(new FileManagerFile(this, folder, file.Name, file.Id, fileProperties));
        }
        return result;
    }
    public override IEnumerable<FileManagerFolder> GetFolders(FileManagerFolder parentFolder) {
        List<FileManagerFolder> result = new List<FileManagerFolder>();
        foreach(FileManagerFolder folder in base.GetFolders(parentFolder)) {
            var folderInfo = new FileInfo(MapPath(folder.FullName));
            FileManagerFolderProperties folderProperties = new FileManagerFolderProperties() {
                Metadata = new Dictionary<string, object>()
            };
            var folderSecurity = File.GetAccessControl(MapPath(folder.FullName));
            folderProperties.Metadata.Add("Name", folder.Name);
            folderProperties.Metadata.Add("Type", "Folder");
            var directoryInfo = new DirectoryInfo(MapPath(folder.FullName));
            var filesInfo = directoryInfo.GetFiles("*", SearchOption.AllDirectories);
            long folderSize = 0;
            foreach (var info in filesInfo)
                folderSize += info.Length;
            var filesCount = filesInfo.Length;
            var subDirectoriesCount = directoryInfo.GetDirectories("*", SearchOption.AllDirectories).Length;
            folderProperties.Metadata.Add("Size", folderSize.ToString("#,#") + " bytes");
            folderProperties.Metadata.Add("Contains", string.Format("Files: {0}, Folders: {1}", filesCount, subDirectoriesCount));
            folderProperties.Metadata.Add("Created", folderInfo.CreationTime.ToString("U"));
            folderProperties.Metadata.Add("Modified", folderInfo.LastWriteTime.ToString("U"));
            folderProperties.Metadata.Add("Accessed", folderInfo.LastAccessTime.ToString("U"));
            folderProperties.Metadata.Add("Attributes", folderInfo.Attributes);
            result.Add(new FileManagerFolder(this, parentFolder, folder.Name, folder.Id, folderProperties));
        }
        return result;
    }
}
Screen Size
Color Themes
Demo QR Code