2010-04-24 08:39:23 +08:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using Microsoft.WindowsAzure;
|
|
|
|
|
using Microsoft.WindowsAzure.StorageClient;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using Orchard.Storage;
|
|
|
|
|
|
2010-04-27 05:58:29 +08:00
|
|
|
|
namespace Orchard.Azure.Storage {
|
|
|
|
|
public interface IDependency { }
|
2010-04-24 08:39:23 +08:00
|
|
|
|
|
2010-04-27 05:58:29 +08:00
|
|
|
|
public class AzureBlobStorageProvider : IStorageProvider {
|
2010-04-27 07:46:55 +08:00
|
|
|
|
public const string ContainerName = "media"; // container names must be lower cased
|
|
|
|
|
|
2010-04-24 08:39:23 +08:00
|
|
|
|
private readonly CloudStorageAccount _storageAccount;
|
2010-04-27 07:46:55 +08:00
|
|
|
|
private string _shellName;
|
2010-04-24 08:39:23 +08:00
|
|
|
|
public CloudBlobClient BlobClient { get; private set; }
|
|
|
|
|
public CloudBlobContainer Container { get; private set; }
|
|
|
|
|
|
2010-04-27 07:46:55 +08:00
|
|
|
|
public AzureBlobStorageProvider(string shellName)
|
|
|
|
|
: this(shellName, CloudStorageAccount.FromConfigurationSetting("DataConnectionString")) {
|
2010-04-24 08:39:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 07:46:55 +08:00
|
|
|
|
public AzureBlobStorageProvider(string shellName, CloudStorageAccount storageAccount) {
|
2010-04-24 08:39:23 +08:00
|
|
|
|
// Setup the connection to custom storage accountm, e.g. Development Storage
|
|
|
|
|
_storageAccount = storageAccount;
|
|
|
|
|
|
2010-04-27 07:46:55 +08:00
|
|
|
|
_shellName = shellName;
|
|
|
|
|
|
2010-04-24 08:39:23 +08:00
|
|
|
|
BlobClient = _storageAccount.CreateCloudBlobClient();
|
|
|
|
|
// Get and create the container if it does not exist
|
|
|
|
|
// The container is named with DNS naming restrictions (i.e. all lower case)
|
2010-04-27 07:46:55 +08:00
|
|
|
|
Container = BlobClient.GetContainerReference(ContainerName);
|
2010-04-27 05:58:29 +08:00
|
|
|
|
Container.CreateIfNotExist();
|
2010-04-24 08:39:23 +08:00
|
|
|
|
|
2010-04-27 02:02:10 +08:00
|
|
|
|
Container.SetPermissions(new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Container });
|
2010-04-24 08:39:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 07:46:55 +08:00
|
|
|
|
private static void EnsurePathIsRelative(string path) {
|
|
|
|
|
if ( path.StartsWith("/") || path.StartsWith("http://"))
|
|
|
|
|
throw new ArgumentException("Path must be relative");
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-24 08:39:23 +08:00
|
|
|
|
public IStorageFile GetFile(string path) {
|
2010-04-27 07:46:55 +08:00
|
|
|
|
EnsurePathIsRelative(path);
|
|
|
|
|
Container.EnsureBlobExists(path);
|
2010-04-24 08:39:23 +08:00
|
|
|
|
return new AzureBlobFileStorage(Container.GetBlockBlobReference(path));
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 05:58:29 +08:00
|
|
|
|
public IEnumerable<IStorageFile> ListFiles(string path) {
|
2010-04-27 07:46:55 +08:00
|
|
|
|
EnsurePathIsRelative(path);
|
2010-04-27 05:58:29 +08:00
|
|
|
|
|
2010-04-27 07:46:55 +08:00
|
|
|
|
string prefix = String.Concat(Container.Name, "/", _shellName, "/", path);
|
2010-04-27 05:58:29 +08:00
|
|
|
|
if ( !prefix.EndsWith("/") )
|
|
|
|
|
prefix += "/";
|
|
|
|
|
|
|
|
|
|
foreach ( var blobItem in BlobClient.ListBlobsWithPrefix(prefix).OfType<CloudBlockBlob>() ) {
|
2010-04-24 08:39:23 +08:00
|
|
|
|
yield return new AzureBlobFileStorage(blobItem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 05:58:29 +08:00
|
|
|
|
public IEnumerable<IStorageFolder> ListFolders(string path) {
|
2010-04-27 07:46:55 +08:00
|
|
|
|
EnsurePathIsRelative(path);
|
|
|
|
|
path = String.Concat(_shellName, "/", path);
|
|
|
|
|
|
|
|
|
|
if ( !Container.DirectoryExists(path) ) {
|
2010-04-24 08:39:23 +08:00
|
|
|
|
try {
|
|
|
|
|
CreateFolder(path);
|
|
|
|
|
}
|
2010-04-27 05:58:29 +08:00
|
|
|
|
catch ( Exception ex ) {
|
2010-04-24 08:39:23 +08:00
|
|
|
|
throw new ArgumentException(string.Format("The folder could not be created at path: {0}. {1}", path, ex));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Container.GetDirectoryReference(path)
|
|
|
|
|
.ListBlobs()
|
|
|
|
|
.OfType<CloudBlobDirectory>()
|
|
|
|
|
.Select<CloudBlobDirectory, IStorageFolder>(d => new AzureBlobFolderStorage(d))
|
|
|
|
|
.ToList();
|
2010-04-27 05:58:29 +08:00
|
|
|
|
}
|
2010-04-24 08:39:23 +08:00
|
|
|
|
|
|
|
|
|
public void CreateFolder(string path) {
|
2010-04-27 07:46:55 +08:00
|
|
|
|
EnsurePathIsRelative(path);
|
|
|
|
|
path = String.Concat(_shellName, "/", path);
|
|
|
|
|
|
|
|
|
|
Container.EnsureDirectoryDoesNotExist(path);
|
2010-04-24 08:39:23 +08:00
|
|
|
|
Container.GetDirectoryReference(path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void DeleteFolder(string path) {
|
2010-04-27 07:46:55 +08:00
|
|
|
|
EnsurePathIsRelative(path);
|
|
|
|
|
path = String.Concat(_shellName, "/", path);
|
|
|
|
|
|
|
|
|
|
Container.EnsureDirectoryExists(path);
|
2010-04-27 05:58:29 +08:00
|
|
|
|
foreach ( var blob in Container.GetDirectoryReference(path).ListBlobs() ) {
|
|
|
|
|
if ( blob is CloudBlob )
|
|
|
|
|
( (CloudBlob)blob ).Delete();
|
2010-04-24 08:39:23 +08:00
|
|
|
|
|
2010-04-27 05:58:29 +08:00
|
|
|
|
if ( blob is CloudBlobDirectory )
|
2010-04-27 07:46:55 +08:00
|
|
|
|
DeleteFolder(blob.Uri.ToString().Substring(Container.Uri.ToString().Length + 2 + _shellName.Length));
|
2010-04-24 08:39:23 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void RenameFolder(string path, string newPath) {
|
2010-04-27 07:46:55 +08:00
|
|
|
|
EnsurePathIsRelative(path);
|
|
|
|
|
|
|
|
|
|
EnsurePathIsRelative(newPath);
|
2010-04-24 08:39:23 +08:00
|
|
|
|
|
|
|
|
|
if ( !path.EndsWith("/") )
|
|
|
|
|
path += "/";
|
|
|
|
|
|
|
|
|
|
if ( !newPath.EndsWith("/") )
|
|
|
|
|
newPath += "/";
|
|
|
|
|
|
2010-04-27 07:46:55 +08:00
|
|
|
|
foreach ( var blob in Container.GetDirectoryReference(_shellName + "/" + path).ListBlobs() ) {
|
2010-04-24 08:39:23 +08:00
|
|
|
|
if ( blob is CloudBlob ) {
|
|
|
|
|
string filename = Path.GetFileName(blob.Uri.ToString());
|
|
|
|
|
string source = String.Concat(path, filename);
|
|
|
|
|
string destination = String.Concat(newPath, filename);
|
|
|
|
|
RenameFile(source, destination);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( blob is CloudBlobDirectory ) {
|
|
|
|
|
string foldername = blob.Uri.Segments.Last();
|
|
|
|
|
string source = String.Concat(path, foldername);
|
|
|
|
|
string destination = String.Concat(newPath, foldername);
|
|
|
|
|
RenameFolder(source, destination);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void DeleteFile(string path) {
|
2010-04-27 07:46:55 +08:00
|
|
|
|
EnsurePathIsRelative(path);
|
|
|
|
|
path = String.Concat(_shellName, "/", path);
|
|
|
|
|
|
|
|
|
|
Container.EnsureBlobExists(path);
|
2010-04-24 08:39:23 +08:00
|
|
|
|
var blob = Container.GetBlockBlobReference(path);
|
|
|
|
|
blob.Delete();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void RenameFile(string path, string newPath) {
|
2010-04-27 07:46:55 +08:00
|
|
|
|
EnsurePathIsRelative(path);
|
|
|
|
|
path = String.Concat(_shellName, "/", path);
|
|
|
|
|
|
|
|
|
|
EnsurePathIsRelative(newPath);
|
|
|
|
|
newPath = String.Concat(_shellName, "/", newPath);
|
|
|
|
|
|
|
|
|
|
Container.EnsureBlobExists(path);
|
|
|
|
|
Container.EnsureBlobDoesNotExist(newPath);
|
2010-04-24 08:39:23 +08:00
|
|
|
|
|
|
|
|
|
var blob = Container.GetBlockBlobReference(path);
|
|
|
|
|
var newBlob = Container.GetBlockBlobReference(newPath);
|
|
|
|
|
newBlob.CopyFromBlob(blob);
|
|
|
|
|
blob.Delete();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IStorageFile CreateFile(string path) {
|
2010-04-27 07:46:55 +08:00
|
|
|
|
EnsurePathIsRelative(path);
|
|
|
|
|
path = String.Concat(_shellName, "/", path);
|
|
|
|
|
|
|
|
|
|
if ( Container.BlobExists(path) ) {
|
2010-04-24 08:39:23 +08:00
|
|
|
|
throw new ArgumentException("File " + path + " already exists");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var blob = Container.GetBlockBlobReference(path);
|
|
|
|
|
blob.OpenWrite().Dispose(); // force file creation
|
|
|
|
|
return new AzureBlobFileStorage(blob);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private class AzureBlobFileStorage : IStorageFile {
|
|
|
|
|
private readonly CloudBlockBlob _blob;
|
|
|
|
|
|
|
|
|
|
public AzureBlobFileStorage(CloudBlockBlob blob) {
|
|
|
|
|
_blob = blob;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string GetPath() {
|
|
|
|
|
return _blob.Uri.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string GetName() {
|
|
|
|
|
return Path.GetFileName(GetPath());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public long GetSize() {
|
|
|
|
|
return _blob.Properties.Length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public DateTime GetLastUpdated() {
|
|
|
|
|
return _blob.Properties.LastModifiedUtc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string GetFileType() {
|
|
|
|
|
return Path.GetExtension(GetPath());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Stream OpenRead() {
|
|
|
|
|
return _blob.OpenRead();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Stream OpenWrite() {
|
|
|
|
|
return _blob.OpenWrite();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private class AzureBlobFolderStorage : IStorageFolder {
|
|
|
|
|
private readonly CloudBlobDirectory _blob;
|
|
|
|
|
|
|
|
|
|
public AzureBlobFolderStorage(CloudBlobDirectory blob) {
|
|
|
|
|
_blob = blob;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string GetName() {
|
|
|
|
|
return _blob.Uri.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public long GetSize() {
|
|
|
|
|
return GetDirectorySize(_blob);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public DateTime GetLastUpdated() {
|
|
|
|
|
return DateTime.MinValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IStorageFolder GetParent() {
|
2010-04-27 05:58:29 +08:00
|
|
|
|
if ( _blob.Parent != null ) {
|
2010-04-24 08:39:23 +08:00
|
|
|
|
return new AzureBlobFolderStorage(_blob.Parent);
|
|
|
|
|
}
|
|
|
|
|
throw new ArgumentException("Directory " + _blob.Uri + " does not have a parent directory");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static long GetDirectorySize(CloudBlobDirectory directoryBlob) {
|
|
|
|
|
long size = 0;
|
|
|
|
|
|
2010-04-27 05:58:29 +08:00
|
|
|
|
foreach ( var blobItem in directoryBlob.ListBlobs() ) {
|
|
|
|
|
if ( blobItem is CloudBlob )
|
|
|
|
|
size += ( (CloudBlob)blobItem ).Properties.Length;
|
2010-04-24 08:39:23 +08:00
|
|
|
|
|
2010-04-27 05:58:29 +08:00
|
|
|
|
if ( blobItem is CloudBlobDirectory )
|
2010-04-24 08:39:23 +08:00
|
|
|
|
size += GetDirectorySize((CloudBlobDirectory)blobItem);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return size;
|
|
|
|
|
}
|
2010-04-27 05:58:29 +08:00
|
|
|
|
}
|
2010-04-24 08:39:23 +08:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|