Your search did not match any results.
File Manager

Azure Server-Side Binding

This demo illustrates how to configure the FileManager to manage files and folders in Microsoft Azure Blob Storage. To access the Azure Blob Storage, the component uses the Remote File System Provider. This file system provider allows you to access the storage's file system on the client side. To process the HTTP requests on the server, create your own file system provider that implements the IFileSystemItemLoader, IFileSystemItemEditor, IFileUploader and IFileContentProvider interfaces.

Backend API
Copy to CodeSandBox
Apply
Reset
<template> <div id="wrapper" :class="wrapperClassName" > <DxLoadPanel :position="loadPanelPosition" v-model:visible="loadPanelVisible" /> <DxFileManager id="file-manager" :file-system-provider="fileSystemProvider" :allowed-file-extensions="allowedFileExtensions" > <!-- uncomment the code below to enable file/directory management --> <!-- <dx-permissions :create="true" :copy="true" :move="true" :delete="true" :rename="true" :upload="true" :download="true" /> --> </DxFileManager> <div id="message-box"> To run the demo locally, specify your Azure storage account name, access key and container name in the web.config file. Refer to the <a href="https://js.devexpress.com/Demos/WidgetsGallery/Demo/FileManager/AzureServerBinding/Vue/Light/" target="_blank" > https://js.devexpress.com/Demos/WidgetsGallery/Demo/FileManager/AzureServerBinding/Vue/Light/ </a> to see the demo online. </div> </div> </template> <script> import { DxFileManager, DxPermissions } from 'devextreme-vue/file-manager'; import RemoteFileSystemProvider from 'devextreme/file_management/remote_provider'; import { DxLoadPanel } from 'devextreme-vue/load-panel'; const fileSystemProvider = new RemoteFileSystemProvider({ endpointUrl: 'https://js.devexpress.com/Demos/Mvc/api/file-manager-azure', }); const allowedFileExtensions = []; export default { components: { DxFileManager, DxPermissions, DxLoadPanel, }, data() { return { fileSystemProvider, allowedFileExtensions, loadPanelPosition: { of: '#file-manager' }, loadPanelVisible: true, wrapperClassName: '', }; }, created() { fetch('https://js.devexpress.com/Demos/Mvc/api/file-manager-azure-status?widgetType=fileManager') .then((response) => response.json()) .then((result) => { this.wrapperClassName = result.active ? 'show-widget' : 'show-message'; this.loadPanelVisible = false; }); }, }; </script> <style> #wrapper #file-manager { visibility: hidden; } #wrapper #message-box { display: none; } #wrapper.show-widget #file-manager { visibility: visible; } #wrapper.show-message #file-manager { display: none; } #wrapper.show-message #message-box { display: block; } </style>
import { createApp } from 'vue'; import App from './App.vue'; createApp(App).mount('#app');
<!DOCTYPE html> <html> <head> <title>DevExtreme Demo</title> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/22.1.5/css/dx.common.css" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/22.1.5/css/dx.light.css" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/22.1.5/css/dx-gantt.css" /> <script src="https://unpkg.com/core-js@2.4.1/client/shim.min.js"></script> <script src="https://unpkg.com/systemjs@0.21.3/dist/system.js"></script> <script type="text/javascript" src="config.js"></script> <script type="text/javascript"> System.import("./index.js"); </script> </head> <body class="dx-viewport"> <div class="demo-container"> <div id="app"> </div> </div> </body> </html>
window.config = { transpiler: 'plugin-babel', meta: { '*.vue': { loader: 'vue-loader', }, 'devextreme/localization.js': { 'esModule': true, }, }, paths: { 'npm:': 'https://unpkg.com/', }, map: { 'vue': 'npm:vue@3.0.0/dist/vue.esm-browser.js', 'vue-loader': 'npm:dx-systemjs-vue-browser@1.0.15/index.js', 'mitt': 'npm:mitt/dist/mitt.umd.js', 'rrule': 'npm:rrule@2.6.4/dist/es5/rrule.js', 'luxon': 'npm:luxon@1.28.0/build/global/luxon.min.js', 'es6-object-assign': 'npm:es6-object-assign@1.1.0', 'devextreme': 'npm:devextreme@22.1.5/cjs', 'devextreme-vue': 'npm:devextreme-vue@22.1.5', 'jszip': 'npm:jszip@3.7.1/dist/jszip.min.js', 'devextreme-quill': 'npm:devextreme-quill@1.5.16/dist/dx-quill.min.js', 'devexpress-diagram': 'npm:devexpress-diagram@2.1.63/dist/dx-diagram.js', 'devexpress-gantt': 'npm:devexpress-gantt@4.1.32/dist/dx-gantt.js', '@devextreme/runtime': 'npm:@devextreme/runtime@3.0.11', 'inferno': 'npm:inferno@7.4.4/dist/inferno.min.js', 'inferno-compat': 'npm:inferno-compat@7.4.11/dist/inferno-compat.min.js', 'inferno-create-element': 'npm:inferno-create-element@7.4.11/dist/inferno-create-element.min.js', 'inferno-dom': 'npm:inferno-dom/dist/inferno-dom.min.js', 'inferno-hydrate': 'npm:inferno-hydrate@7.4.11/dist/inferno-hydrate.min.js', 'inferno-clone-vnode': 'npm:inferno-clone-vnode@7.4.11/dist/inferno-clone-vnode.min.js', 'inferno-create-class': 'npm:inferno-create-class@7.4.11/dist/inferno-create-class.min.js', 'inferno-extras': 'npm:inferno-extras@7.4.11/dist/inferno-extras.min.js', 'plugin-babel': 'npm:systemjs-plugin-babel@0.0.25/plugin-babel.js', 'systemjs-babel-build': 'npm:systemjs-plugin-babel@0.0.25/systemjs-babel-browser.js', // Prettier 'prettier/standalone': 'npm:prettier@2.7.1/standalone.js', 'prettier/parser-html': 'npm:prettier@2.7.1/parser-html.js', }, packages: { 'devextreme-vue': { main: 'index.js', }, 'devextreme': { defaultExtension: 'js', }, 'devextreme/events/utils': { main: 'index', }, 'devextreme/events': { main: 'index', }, 'es6-object-assign': { main: './index.js', defaultExtension: 'js', }, }, packageConfigPaths: [ 'npm:@devextreme/*/package.json', 'npm:@devextreme/runtime@3.0.11/inferno/package.json', ], babelOptions: { sourceMaps: false, stage0: true, }, }; System.config(window.config);
using DevExtreme.AspNet.Mvc.FileManagement; using DevExtreme.MVC.Demos.Models.FileManagement; using System; using System.Net.Http; using System.Web; using System.Web.Http; using System.Web.Mvc; using System.Net.Http.Headers; namespace DevExtreme.MVC.Demos.Controllers.ApiControllers { public class FileManagerAzureProviderApiController : ApiController { HttpContext CurrentContext = HttpContext.Current; string TempDirectoryPath { get { return CurrentContext.Server.MapPath("~/App_Data/UploadTemp"); } } [System.Web.Http.AcceptVerbs("GET", "POST")] [System.Web.Http.Route("api/file-manager-azure", Name = "FileManagementAzureApi")] public HttpResponseMessage Process() { FileSystemCommand command; Enum.TryParse(CurrentContext.Request["command"], out command); string arguments = CurrentContext.Request["arguments"]; AzureStorageAccount account = AzureStorageAccount.FileManager.Value; var provider = new AzureBlobFileProvider(account.AccountName, account.AccessKey, account.ContainerName, TempDirectoryPath); var config = new FileSystemConfiguration { Request = new HttpContextWrapper(CurrentContext).Request, FileSystemProvider = provider, //uncomment the code below to enable file/folder management //AllowCopy = true, //AllowCreate = true, //AllowMove = true, //AllowDelete = true, //AllowRename = true, //AllowUpload = true, AllowDownload = true, UploadConfiguration = new UploadConfiguration { MaxFileSize = 1048576 }, TempDirectory = TempDirectoryPath }; var processor = new FileSystemCommandProcessor(config); var commandResult = processor.Execute(command, arguments); var result = commandResult.GetClientCommandResult(); return command == FileSystemCommand.Download && commandResult.Success ? CreateDownloadResponse(result) : Request.CreateResponse(result); } HttpResponseMessage CreateDownloadResponse(object result) { var fileContent = result as FileStreamResult; if(fileContent == null) return Request.CreateResponse(result); var response = new HttpResponseMessage() { Content = new StreamContent(fileContent.FileStream) }; response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = fileContent.FileDownloadName }; response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); return response; } } }
using DevExtreme.AspNet.Mvc.FileManagement; using System; using System.Collections.Generic; using System.IO; using System.Linq; using Azure; using Azure.Storage; using Azure.Storage.Blobs; using Azure.Storage.Blobs.Models; namespace DevExtreme.MVC.Demos.Models.FileManagement { public class AzureBlobFileProvider : IFileSystemItemLoader, IFileSystemItemEditor, IFileUploader, IFileContentProvider { const string EmptyDirectoryDummyBlobName = "aspxAzureEmptyFolderBlob"; const string TempFilePrefix = "azuredownload_"; const string ServiceUri = "https://{0}.blob.core.windows.net"; const string PathSeparator = "/"; public AzureBlobFileProvider(string storageAccountName, string storageAccessKey, string containerName, string tempDirPath) { StorageAccountName = storageAccountName; StorageAccessKey = storageAccessKey; ContainerName = containerName; TempDirectoryPath = tempDirPath; } string StorageAccountName { get; set; } string StorageAccessKey { get; set; } string ContainerName { get; set; } string TempDirectoryPath { get; set; } BlobContainerClient _container; BlobContainerClient Container { get { if(_container == null) { StorageSharedKeyCredential credential = new StorageSharedKeyCredential(StorageAccountName, StorageAccessKey); BlobServiceClient client = new BlobServiceClient(new Uri(string.Format(ServiceUri, StorageAccountName)), credential); _container = client.GetBlobContainerClient(ContainerName); } return _container; } } public IEnumerable<FileSystemItem> GetItems(FileSystemLoadItemOptions options) { var result = new List<FileSystemItem>(); string dirKey = GetFileItemPath(options.Directory); var oneLevelItemsList = GetOneLevelHierarchyBlobs(dirKey); foreach(BlobHierarchyItem hierarchyItem in oneLevelItemsList) { var fileItem = GetFileSystemItem(hierarchyItem); if(fileItem != null) { result.Add(fileItem); } } return result.OrderByDescending(item => item.IsDirectory) .ThenBy(item => item.Name) .ToList(); } Pageable<BlobHierarchyItem> GetOneLevelHierarchyBlobs(string prefix) { if(!string.IsNullOrEmpty(prefix) && !prefix.EndsWith(PathSeparator)) prefix = prefix + PathSeparator; return Container.GetBlobsByHierarchy(prefix: prefix, delimiter: PathSeparator); } FileSystemItem GetFileSystemItem(BlobHierarchyItem hierarchyItem) { var item = new FileSystemItem(); string name = GetBlobName(hierarchyItem); if(name == EmptyDirectoryDummyBlobName) return null; item.Name = name; if(hierarchyItem.IsBlob) { var blobItem = hierarchyItem.Blob; item.DateModified = blobItem.Properties.LastModified.GetValueOrDefault().DateTime; item.Size = blobItem.Properties.ContentLength ?? 0; } else if(hierarchyItem.IsPrefix) { item.IsDirectory = true; item.HasSubDirectories = GetHasDirectories(hierarchyItem); item.DateModified = DateTime.UtcNow; } else { throw new Exception("Unsupported blob type"); } return item; } bool GetHasDirectories(BlobHierarchyItem dir) { string dirKey = GetBlobRelativePath(dir); var oneLevelItemsList = GetOneLevelHierarchyBlobs(dirKey); return oneLevelItemsList != null && oneLevelItemsList.Any(bItem => bItem.IsPrefix); } public void CreateDirectory(FileSystemCreateDirectoryOptions options) { string path = GetFileItemPath(options.ParentDirectory); string blobKey = $"{options.DirectoryName}{PathSeparator}{EmptyDirectoryDummyBlobName}"; if(!string.IsNullOrEmpty(path)) blobKey = $"{path}{PathSeparator}{blobKey}"; Container.UploadBlob(blobKey, BinaryData.FromString(string.Empty)); } public void RenameItem(FileSystemRenameItemOptions options) { string newName = options.ItemNewName; string key = GetFileItemPath(options.Item); int index = key.LastIndexOf(PathSeparator); string newKey; if(index >= 0) { string parentKey = key.Substring(0, index + 1); newKey = parentKey + newName; } else newKey = newName; Copy(key, newKey, true); } public void MoveItem(FileSystemMoveItemOptions options) { Copy(options.Item, options.DestinationDirectory, true); } public void CopyItem(FileSystemCopyItemOptions options) { Copy(options.Item, options.DestinationDirectory, false); } void Copy(FileSystemItemInfo sourceItem, FileSystemItemInfo destinationItem, bool deleteSource = false) { string sourceKey = GetFileItemPath(sourceItem); string destinationKey = GetFileItemPath(destinationItem) + PathSeparator + sourceItem.Name; Copy(sourceKey, destinationKey, deleteSource); } void Copy(string sourceKey, string destinationKey, bool deleteSource) { var blobClient = Container.GetBlobClient(sourceKey); bool isFile = blobClient.Exists(); if(isFile) CopyFile(blobClient, destinationKey, deleteSource); else CopyDirectory(sourceKey, destinationKey, deleteSource); } public void DeleteItem(FileSystemDeleteItemOptions options) { string key = GetFileItemPath(options.Item); var blobClient = Container.GetBlobClient(key); bool isFile = blobClient.Exists(); if(isFile) RemoveFile(blobClient); else RemoveDirectory(key); } public void UploadFile(FileSystemUploadFileOptions options) { string destinationKey = $"{options.DestinationDirectory.Path}{PathSeparator}{options.FileName}"; var blobClient = Container.GetBlobClient(destinationKey); blobClient.Upload(options.TempFile.FullName, overwrite: true); RemoveUploadedFile(options.TempFile.FullName); } void RemoveFile(BlobClient blob) { blob.Delete(); } void RemoveDirectory(string dirKey) { var children = GetOneLevelHierarchyBlobs(dirKey); foreach(var blob in children) { string childRelativePath = GetBlobRelativePath(blob); if(blob.IsBlob) { RemoveFile(Container.GetBlobClient(childRelativePath)); } else if(blob.IsPrefix) { RemoveDirectory(childRelativePath); } else { throw new Exception("Unsupported blob type"); } } } void CopyFile(BlobClient blob, string destinationKey, bool deleteSource = false) { var blobCopy = Container.GetBlobClient(destinationKey); blobCopy.StartCopyFromUri(blob.Uri); if(deleteSource) blob.Delete(); } void CopyDirectory(string sourceKey, string destinationKey, bool deleteSource = false) { var children = GetOneLevelHierarchyBlobs(sourceKey); foreach(var blob in children) { string childSourceRelativePath = GetBlobRelativePath(blob); string childName = GetBlobName(blob); string childDestinationRelativePath = $"{destinationKey}{PathSeparator}{childName}"; if(blob.IsBlob) { CopyFile(Container.GetBlobClient(childSourceRelativePath), childDestinationRelativePath, deleteSource); } else if(blob.IsPrefix) { CopyDirectory(GetBlobRelativePath(blob), childDestinationRelativePath, deleteSource); } else { throw new Exception("Unsupported blob type"); } } } string GetBlobName(BlobHierarchyItem hierarchyItem) { var relativePath = GetBlobRelativePath(hierarchyItem); return relativePath != null ? GetFileItemName(relativePath) : null; } string GetBlobRelativePath(BlobHierarchyItem hierarchyItem) { if(hierarchyItem.IsBlob) { return hierarchyItem.Blob.Name; } else if(hierarchyItem.IsPrefix) { return hierarchyItem.Prefix.Substring(0, hierarchyItem.Prefix.Length - 1); } else { return null; } } string GetFileItemName(string relativeName) { var lastDelimiterIndex = relativeName.LastIndexOf(PathSeparator) == -1 ? 0 : relativeName.LastIndexOf(PathSeparator) + 1; return relativeName.Substring(lastDelimiterIndex); } string GetFileItemPath(FileSystemItemInfo item) { return item.Path.Replace("\\", PathSeparator); } public void RemoveUploadedFile(string fileFullPath) { FileInfo file = new FileInfo(fileFullPath); file.Delete(); } public Stream GetFileContent(FileSystemLoadFileContentOptions options) { if(!Directory.Exists(TempDirectoryPath)) Directory.CreateDirectory(TempDirectoryPath); CleanUpDownloadedFiles(); string tempFileName = string.Format("{0}{1}.tmp", TempFilePrefix, Guid.NewGuid().ToString("N")); string tempFilePath = Path.Combine(TempDirectoryPath, tempFileName); string key = GetFileItemPath(options.File); var blob = Container.GetBlobClient(key); blob.DownloadTo(tempFilePath); return File.Open(tempFilePath, FileMode.Open, FileAccess.Read, FileShare.Read); } void CleanUpDownloadedFiles() { var timeout = TimeSpan.FromMinutes(10); try { var dir = new DirectoryInfo(TempDirectoryPath); var files = dir.GetFiles(TempFilePrefix + "*.tmp") .Where(file => DateTime.UtcNow - file.LastWriteTimeUtc > timeout); foreach(FileInfo file in files) { try { file.Delete(); } catch { } } } catch { } } } }