Your search did not match any results.
File Uploader

Direct Upload to Azure

The FileUploader component supports direct-upload to blob storages. This demo illustrates how to configure the uploadChunk property to upload a large file directly to Azure Blob Storage without using a user's web server. All APIs that implement access to Azure Blob Storage on the client are stored in the azure.file.system.js file (app.service.ts - for Angular framework).

To implement file upload logic, use the uploadChunk property to specify how to process a connection request to the storage.

Backend API
Copy to CodePen
Apply
Reset
class AzureFileSystem { constructor(azureGateway) { this.gateway = azureGateway; this.EMPTY_DIR_DUMMY_BLOB_NAME = 'aspxAzureEmptyFolderBlob'; } getItems(path) { var prefix = this.getDirectoryBlobName(path); return this.gateway.getBlobList(prefix).then((entries) => this.getDataObjectsFromEntries(entries, prefix)); } createDirectory(path, name) { var blobName = path ? `${path}/${name}` : name; return this.gateway.createDirectoryBlob(blobName); } renameFile(path, name) { var newPath = this.getPathWithNewName(path, name); return this.moveFile(path, newPath); } renameDirectory(path, name) { var newPath = this.getPathWithNewName(path, name); return this.moveDirectory(path, newPath); } getPathWithNewName(path, name) { var parts = path.split('/'); parts[parts.length - 1] = name; return parts.join('/'); } deleteFile(path) { return this.gateway.deleteBlob(path); } deleteDirectory(path) { var prefix = this.getDirectoryBlobName(path); return this.executeActionForEachEntry(prefix, (entry) => this.gateway.deleteBlob(entry.name)); } copyFile(sourcePath, destinationPath) { return this.gateway.copyBlob(sourcePath, destinationPath); } copyDirectory(sourcePath, destinationPath) { var prefix = this.getDirectoryBlobName(sourcePath); var destinationKey = this.getDirectoryBlobName(destinationPath); return this.executeActionForEachEntry(prefix, (entry) => this.copyEntry(entry, prefix, destinationKey)); } copyEntry(entry, sourceKey, destinationKey) { var restName = entry.name.substr(sourceKey.length); var newDestinationKey = destinationKey + restName; return this.gateway.copyBlob(entry.name, newDestinationKey); } moveFile(sourcePath, destinationPath) { return this.gateway.copyBlob(sourcePath, destinationPath).then(() => this.gateway.deleteBlob(sourcePath)); } moveDirectory(sourcePath, destinationPath) { var prefix = this.getDirectoryBlobName(sourcePath); var destinationKey = this.getDirectoryBlobName(destinationPath); return this.executeActionForEachEntry(prefix, (entry) => this.copyEntry(entry, prefix, destinationKey).then(() => this.gateway.deleteBlob(entry.name))); } downloadFile(path) { this.gateway.getBlobUrl(path).then((accessUrls) => { window.location.href = accessUrls.url1; }); } executeActionForEachEntry(prefix, action) { return this.gateway.getBlobList(prefix).then((entries) => { var deferreds = entries.map((entry) => action(entry)); return Promise.all(deferreds); }); } getDataObjectsFromEntries(entries, prefix) { var result = []; var directories = {}; entries.forEach((entry) => { var restName = entry.name.substr(prefix.length); var parts = restName.split('/'); if (parts.length === 1) { if (restName !== this.EMPTY_DIR_DUMMY_BLOB_NAME) { var obj = { name: restName, isDirectory: false, dateModified: entry.lastModified, size: entry.length, }; result.push(obj); } } else { var dirName = parts[0]; var directory = directories[dirName]; if (!directory) { directory = { name: dirName, isDirectory: true, }; directories[dirName] = directory; result.push(directory); } if (!directory.hasSubDirectories) { directory.hasSubDirectories = parts.length > 2; } } }); result.sort(this.compareDataObjects); return result; } compareDataObjects(obj1, obj2) { if (obj1.isDirectory === obj2.isDirectory) { var name1 = obj1.name.toLowerCase(); var name2 = obj2.name.toLowerCase(); if (name1 < name2) { return -1; } return name1 > name2 ? 1 : 0; } return obj1.isDirectory ? -1 : 1; } getDirectoryBlobName(path) { return path ? `${path}/` : path; } } class AzureGateway { constructor(endpointUrl, onRequestExecuted) { this.endpointUrl = endpointUrl; this.onRequestExecuted = onRequestExecuted; } getBlobList(prefix) { return this.getAccessUrl('BlobList') .then((accessUrls) => this.executeBlobListRequest(accessUrls.url1, prefix)) .then((xml) => this.parseEntryListResult(xml)); } parseEntryListResult(xmlString) { var xml = new DOMParser().parseFromString(xmlString, 'text/xml'); return Array.from(xml.querySelectorAll('Blob')).map(this.parseEntry); } parseEntry(xmlEntry) { var entry = {}; entry.etag = xmlEntry.querySelector('Etag').textContent; entry.name = xmlEntry.querySelector('Name').textContent; var dateStr = xmlEntry.querySelector('Last-Modified').textContent; entry.lastModified = new Date(dateStr); var lengthStr = xmlEntry.querySelector('Content-Length').textContent; entry.length = parseInt(lengthStr, 10); return entry; } executeBlobListRequest(accessUrl, prefix) { var params = { restype: 'container', comp: 'list', }; if (prefix) { params.prefix = prefix; } return this.executeRequest(accessUrl, params); } createDirectoryBlob(name) { return this.getAccessUrl('CreateDirectory', name).then((accessUrls) => this.executeRequest({ url: accessUrls.url1, method: 'PUT', headers: { 'x-ms-blob-type': 'BlockBlob', }, processData: false, contentType: false, })); } deleteBlob(name) { return this.getAccessUrl('DeleteBlob', name).then((accessUrls) => this.executeRequest({ url: accessUrls.url1, method: 'DELETE', })); } copyBlob(sourceName, destinationName) { return this.getAccessUrl('CopyBlob', sourceName, destinationName).then((accessUrls) => this.executeRequest({ url: accessUrls.url2, method: 'PUT', headers: { 'x-ms-copy-source': accessUrls.url1, }, })); } putBlock(uploadUrl, blockIndex, blockBlob) { var blockId = this.getBlockId(blockIndex); var params = { comp: 'block', blockid: blockId, }; return this.executeRequest({ url: uploadUrl, method: 'PUT', data: blockBlob, processData: false, contentType: false, }, params); } putBlockList(uploadUrl, blockCount) { var content = this.getBlockListContent(blockCount); var params = { comp: 'blocklist', }; return this.executeRequest({ url: uploadUrl, method: 'PUT', data: content, }, params); } getBlockListContent(blockCount) { var contentParts = [ '<?xml version="1.0" encoding="utf-8"?>', '<BlockList>', ]; for (var i = 0; i < blockCount; i++) { var blockContent = ` <Latest>${this.getBlockId(i)}</Latest>`; contentParts.push(blockContent); } contentParts.push('</BlockList>'); return contentParts.join('\n'); } getBlockId(blockIndex) { var res = `${blockIndex}`; while (res.length < 10) { res = `0${res}`; } return btoa(res); } getUploadAccessUrl(blobName) { return this.getAccessUrl('UploadBlob', blobName); } getBlobUrl(blobName) { return this.getAccessUrl('GetBlob', blobName); } getAccessUrl(command, blobName, blobName2) { var url = `${this.endpointUrl}?command=${command}`; if (blobName) { url += `&blobName=${encodeURIComponent(blobName)}`; } if (blobName2) { url += `&blobName2=${encodeURIComponent(blobName2)}`; } // eslint-disable-next-line no-async-promise-executor return new Promise(async (resolve, reject) => { await this.executeRequest(url).then((x) => { if (x.success) { resolve({ url1: x.accessUrl, url2: x.accessUrl2 }); } else { reject(x.error); } }); }); } executeRequest(args, commandParams) { var ajaxArgs = typeof args === 'string' ? { url: args } : args; var method = ajaxArgs.method || 'GET'; var urlParts = ajaxArgs.url.split('?'); var urlPath = urlParts[0]; var restQueryString = urlParts[1]; var commandQueryString = commandParams ? this.getQueryString(commandParams) : ''; var queryString = commandQueryString || ''; if (restQueryString) { queryString += queryString ? `&${restQueryString}` : restQueryString; } ajaxArgs.url = queryString ? `${urlPath}?${queryString}` : urlPath; return fetch(ajaxArgs.url, ajaxArgs) .then((x) => { var eventArgs = { method, urlPath, queryString, }; if (this.onRequestExecuted) { this.onRequestExecuted(eventArgs); } return x; }) .then(async (x) => { if (x.status === 200) { var text = await x.text(); try { return Object.assign({ success: true }, JSON.parse(text)); } catch (ex) { return text; } } else { return { error: x.statusText }; } }); } getQueryString(params) { return Object.keys(params) .map((key) => `${key}=${encodeURIComponent(params[key])}`) .join('&'); } }
$(() => { const loadPanel = $('#load-panel').dxLoadPanel({ position: { of: '#file-uploader' }, }).dxLoadPanel('instance'); $.ajax({ url: 'https://js.devexpress.com/Demos/Mvc/api/file-manager-azure-status?widgetType=fileUploader', success(result) { const className = result.active ? 'show-widget' : 'show-message'; $('#wrapper').addClass(className); loadPanel.hide(); }, }); const endpointUrl = 'https://js.devexpress.com/Demos/Mvc/api/file-uploader-azure-access'; gateway = new AzureGateway(endpointUrl, onRequestExecuted); $('#file-uploader').dxFileUploader({ chunkSize: 200000, maxFileSize: 1048576, uploadChunk, }); }); function uploadChunk(file, uploadInfo) { let deferred = null; if (uploadInfo.chunkIndex === 0) { deferred = gateway.getUploadAccessUrl(file.name).done((accessUrl) => { uploadInfo.customData.accessUrl = accessUrl; }); } else { deferred = $.Deferred().resolve().promise(); } deferred = deferred.then(() => gateway.putBlock( uploadInfo.customData.accessUrl, uploadInfo.chunkIndex, uploadInfo.chunkBlob, )); if (uploadInfo.chunkIndex === uploadInfo.chunkCount - 1) { deferred = deferred.then(() => gateway.putBlockList( uploadInfo.customData.accessUrl, uploadInfo.chunkCount, )); } return deferred.promise(); } function onRequestExecuted(e) { $('<div>').addClass('request-info').append( createParameterInfoDiv('Method:', e.method), createParameterInfoDiv('Url path:', e.urlPath), createParameterInfoDiv('Query string:', e.queryString), $('<br>'), ) .prependTo('#request-panel'); } function createParameterInfoDiv(name, value) { return $('<div>').addClass('parameter-info').append( $('<div>').addClass('parameter-name').text(name), $('<div>').addClass('parameter-value dx-theme-accent-as-text-color').text(value).attr('title', value), ); } let gateway = null;
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <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" /> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script>window.jQuery || document.write(decodeURIComponent('%3Cscript src="js/jquery.min.js"%3E%3C/script%3E'))</script> <script src="external/azure.file.system.js"></script> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/22.2.3/css/dx.light.css" /> <script src="https://cdn3.devexpress.com/jslib/22.2.3/js/dx.all.js"></script> <link rel="stylesheet" type="text/css" href="styles.css" /> <script src="data.js"></script> <script src="index.js"></script> </head> <body class="dx-viewport"> <div class="demo-container"> <div id="wrapper"> <div id="widget-area"> <div id="file-uploader"></div> <div id="request-panel"></div> </div> <div id="load-panel"></div> <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/FileUploader/AzureDirectUploading/jQuery/Light/" target="_blank"> https://js.devexpress.com/Demos/WidgetsGallery/Demo/FileUploader/AzureDirectUploading/jQuery/Light/</a > to see the demo online. </div> </div> </div> </body> </html>
#widget-area { visibility: hidden; } #message-box { display: none; } .show-widget #widget-area { visibility: visible; } .show-message #widget-area { display: none; } .show-message #message-box { display: block; } #request-panel { min-width: 505px; height: 400px; overflow-x: hidden; overflow-y: auto; padding: 18px; margin-top: 40px; background-color: rgba(191, 191, 191, 0.15); } #request-panel .parameter-info { display: flex; } .request-info .parameter-name { flex: 0 0 100px; } .request-info .parameter-name, .request-info .parameter-value { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
using DevExtreme.MVC.Demos.Models.FileManagement; using System; using System.Net.Http; using System.Web.Http; using Azure.Storage; using Azure.Storage.Sas; using Azure.Storage.Blobs; using Azure.Storage.Blobs.Specialized; namespace DevExtreme.MVC.Demos.Controllers.ApiControllers { public class FileUploaderAzureAccessApiController : ApiController { const long MaxBlobSize = 1048576; const string ServiceUri = "https://{0}.blob.core.windows.net"; BlobServiceClient _client; BlobServiceClient Client { get { if(_client == null) { AzureStorageAccount accountModel = AzureStorageAccount.FileUploader.Value; StorageSharedKeyCredential credential = new StorageSharedKeyCredential(accountModel.AccountName, accountModel.AccessKey); _client = new BlobServiceClient(new Uri(string.Format(ServiceUri, accountModel.AccountName)), credential); } return _client; } } BlobContainerClient _container; BlobContainerClient Container { get { if(_container == null) { AzureStorageAccount accountModel = AzureStorageAccount.FileUploader.Value; _container = Client.GetBlobContainerClient(accountModel.ContainerName); } return _container; } } [HttpGet] [Route("api/file-uploader-azure-access", Name = "FileUploaderAzureAccessApi")] public object Process(string command, string blobName) { try { return UploadBlob(blobName); } catch { return CreateErrorResult(); } } object UploadBlob(string blobName) { if(blobName.Contains("/")) return CreateErrorResult("Invalid blob name."); string prefix = Guid.NewGuid().ToString("N"); string fullBlobName = $"{prefix}_{blobName}"; var blob = Container.GetBlockBlobClient(fullBlobName); if(blob.Exists() && blob.GetProperties().Value.ContentLength > MaxBlobSize) { return CreateErrorResult(); } if(blob.CanGenerateSasUri) { var sasUri = blob.GenerateSasUri(BlobSasPermissions.Write, DateTimeOffset.UtcNow.AddHours(1)); return CreateSuccessResult(sasUri.AbsoluteUri); } else { return CreateErrorResult("BlobClient cannot generate SasUri"); } } object CreateSuccessResult(string url, string url2 = null) { return new { success = true, accessUrl = url, accessUrl2 = url2 }; } object CreateErrorResult(string error = null) { if(string.IsNullOrEmpty(error)) error = "Unspecified error."; return new { success = false, error = error }; } } }