From e375077f04ab0b1815750b79c5974ef50dcc1632 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Fri, 10 Dec 2010 12:53:02 -0800 Subject: [PATCH] Using AzureFileSystem in AzureShellSettingsManager --HG-- branch : dev --- src/Orchard.Azure.Tests/App.config | 5 +- .../AzureVirtualEnvironmentTest.cs | 10 +- .../AzureShellSettingsManagerTests.cs | 45 ++++--- .../Media/AzureBlobStorageProviderTests.cs | 8 +- src/Orchard.Azure/AzureFileSystem.cs | 34 ++--- .../AzureShellSettingsManager.cs | 118 +++++++----------- src/Orchard.Azure/Orchard.Azure.5.0.ReSharper | 108 ++++++++++++++++ .../ServiceDefinition.csdef | 7 ++ 8 files changed, 216 insertions(+), 119 deletions(-) create mode 100644 src/Orchard.Azure/Orchard.Azure.5.0.ReSharper diff --git a/src/Orchard.Azure.Tests/App.config b/src/Orchard.Azure.Tests/App.config index 61487f367..41aa17680 100644 --- a/src/Orchard.Azure.Tests/App.config +++ b/src/Orchard.Azure.Tests/App.config @@ -3,4 +3,7 @@ - + + + + diff --git a/src/Orchard.Azure.Tests/AzureVirtualEnvironmentTest.cs b/src/Orchard.Azure.Tests/AzureVirtualEnvironmentTest.cs index 6a19547b8..73ab3b121 100644 --- a/src/Orchard.Azure.Tests/AzureVirtualEnvironmentTest.cs +++ b/src/Orchard.Azure.Tests/AzureVirtualEnvironmentTest.cs @@ -1,6 +1,8 @@ -using System.Configuration; +using System.ComponentModel; +using System.Configuration; using System.Diagnostics; using System.IO; +using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.StorageClient; using NUnit.Framework; @@ -35,7 +37,11 @@ namespace Orchard.Azure.Tests { _dsService.Close(); } - protected void DeleteAllBlobs(CloudBlobContainer container) { + protected void DeleteAllBlobs(string containerName, CloudStorageAccount account) + { + var blobClient = account.CreateCloudBlobClient(); + var container = blobClient.GetContainerReference(containerName); + foreach ( var blob in container.ListBlobs() ) { if ( blob is CloudBlob ) { ( (CloudBlob)blob ).DeleteIfExists(); diff --git a/src/Orchard.Azure.Tests/Environment/Configuration/AzureShellSettingsManagerTests.cs b/src/Orchard.Azure.Tests/Environment/Configuration/AzureShellSettingsManagerTests.cs index 8c63d172c..f65767ca8 100644 --- a/src/Orchard.Azure.Tests/Environment/Configuration/AzureShellSettingsManagerTests.cs +++ b/src/Orchard.Azure.Tests/Environment/Configuration/AzureShellSettingsManagerTests.cs @@ -8,36 +8,35 @@ namespace Orchard.Azure.Tests.Environment.Configuration { [TestFixture] public class AzureShellSettingsManagerTests : AzureVirtualEnvironmentTest { - protected IShellSettingsManager Loader; + protected CloudStorageAccount DevAccount; + protected IShellSettingsManager ShellSettingsManager; protected override void OnInit() { - CloudStorageAccount devAccount; - CloudStorageAccount.TryParse("UseDevelopmentStorage=true", out devAccount); - - Loader = new AzureShellSettingsManager(devAccount, new Moq.Mock().Object); + CloudStorageAccount.TryParse("UseDevelopmentStorage=true", out DevAccount); + ShellSettingsManager = new AzureShellSettingsManager(DevAccount, new Moq.Mock().Object); } [SetUp] public void Setup() { // ensure default container is empty before running any test - DeleteAllBlobs( ((AzureShellSettingsManager)Loader).Container); + DeleteAllBlobs(AzureShellSettingsManager.ContainerName, DevAccount); } [TearDown] public void TearDown() { // ensure default container is empty after running tests - DeleteAllBlobs(( (AzureShellSettingsManager)Loader ).Container); + DeleteAllBlobs(AzureShellSettingsManager.ContainerName, DevAccount); } [Test] public void SingleSettingsFileShouldComeBackAsExpected() { - Loader.SaveSettings(new ShellSettings { Name = "Default", DataProvider = "SQLite", DataConnectionString = "something else" }); + ShellSettingsManager.SaveSettings(new ShellSettings { Name = "Default", DataProvider = "SQLCe", DataConnectionString = "something else" }); - var settings = Loader.LoadSettings().Single(); + var settings = ShellSettingsManager.LoadSettings().Single(); Assert.That(settings, Is.Not.Null); Assert.That(settings.Name, Is.EqualTo("Default")); - Assert.That(settings.DataProvider, Is.EqualTo("SQLite")); + Assert.That(settings.DataProvider, Is.EqualTo("SQLCe")); Assert.That(settings.DataConnectionString, Is.EqualTo("something else")); } @@ -45,37 +44,37 @@ namespace Orchard.Azure.Tests.Environment.Configuration { [Test] public void MultipleFilesCanBeDetected() { - Loader.SaveSettings(new ShellSettings { Name = "Default", DataProvider = "SQLite", DataConnectionString = "something else" }); - Loader.SaveSettings(new ShellSettings { Name = "Another", DataProvider = "SQLite2", DataConnectionString = "something else2" }); + ShellSettingsManager.SaveSettings(new ShellSettings { Name = "Default", DataProvider = "SQLCe", DataConnectionString = "something else" }); + ShellSettingsManager.SaveSettings(new ShellSettings { Name = "Another", DataProvider = "SQLCe2", DataConnectionString = "something else2" }); - var settings = Loader.LoadSettings(); + var settings = ShellSettingsManager.LoadSettings(); Assert.That(settings.Count(), Is.EqualTo(2)); var def = settings.Single(x => x.Name == "Default"); Assert.That(def.Name, Is.EqualTo("Default")); - Assert.That(def.DataProvider, Is.EqualTo("SQLite")); + Assert.That(def.DataProvider, Is.EqualTo("SQLCe")); Assert.That(def.DataConnectionString, Is.EqualTo("something else")); var alt = settings.Single(x => x.Name == "Another"); Assert.That(alt.Name, Is.EqualTo("Another")); - Assert.That(alt.DataProvider, Is.EqualTo("SQLite2")); + Assert.That(alt.DataProvider, Is.EqualTo("SQLCe2")); Assert.That(alt.DataConnectionString, Is.EqualTo("something else2")); } [Test] public void NewSettingsCanBeStored() { - Loader.SaveSettings(new ShellSettings { Name = "Default", DataProvider = "SQLite", DataConnectionString = "something else" }); + ShellSettingsManager.SaveSettings(new ShellSettings { Name = "Default", DataProvider = "SQLite", DataConnectionString = "something else" }); var foo = new ShellSettings { Name = "Foo", DataProvider = "Bar", DataConnectionString = "Quux" }; - Assert.That(Loader.LoadSettings().Count(), Is.EqualTo(1)); - Loader.SaveSettings(foo); - Assert.That(Loader.LoadSettings().Count(), Is.EqualTo(2)); + Assert.That(ShellSettingsManager.LoadSettings().Count(), Is.EqualTo(1)); + ShellSettingsManager.SaveSettings(foo); + Assert.That(ShellSettingsManager.LoadSettings().Count(), Is.EqualTo(2)); - var text = ( (AzureShellSettingsManager)Loader ).Container.GetBlockBlobReference("Foo/Settings.txt").DownloadText(); - Assert.That(text, Is.StringContaining("Foo")); - Assert.That(text, Is.StringContaining("Bar")); - Assert.That(text, Is.StringContaining("Quux")); + foo = ShellSettingsManager.LoadSettings().Where(s => s.Name == "Foo").Single(); + Assert.That(foo.Name, Is.StringContaining("Foo")); + Assert.That(foo.DataProvider, Is.StringContaining("Bar")); + Assert.That(foo.DataConnectionString, Is.StringContaining("Quux")); } } } diff --git a/src/Orchard.Azure.Tests/FileSystems/Media/AzureBlobStorageProviderTests.cs b/src/Orchard.Azure.Tests/FileSystems/Media/AzureBlobStorageProviderTests.cs index f6e4fda80..256c7c505 100644 --- a/src/Orchard.Azure.Tests/FileSystems/Media/AzureBlobStorageProviderTests.cs +++ b/src/Orchard.Azure.Tests/FileSystems/Media/AzureBlobStorageProviderTests.cs @@ -10,19 +10,19 @@ namespace Orchard.Azure.Tests.FileSystems.Media { [TestFixture] public class AzureBlobStorageProviderTests : AzureVirtualEnvironmentTest { + CloudStorageAccount DevAccount; private AzureBlobStorageProvider _azureBlobStorageProvider; protected override void OnInit() { - CloudStorageAccount devAccount; - CloudStorageAccount.TryParse("UseDevelopmentStorage=true", out devAccount); + CloudStorageAccount.TryParse("UseDevelopmentStorage=true", out DevAccount); - _azureBlobStorageProvider = new AzureBlobStorageProvider(new ShellSettings { Name = "default" }, devAccount); + _azureBlobStorageProvider = new AzureBlobStorageProvider(new ShellSettings { Name = "default" }, DevAccount); } [SetUp] public void Setup() { // ensure default container is empty before running any test - DeleteAllBlobs(_azureBlobStorageProvider.Container); + DeleteAllBlobs(_azureBlobStorageProvider.Container.Name, DevAccount); } [Test] diff --git a/src/Orchard.Azure/AzureFileSystem.cs b/src/Orchard.Azure/AzureFileSystem.cs index 7d1bd11d3..05a42e61e 100644 --- a/src/Orchard.Azure/AzureFileSystem.cs +++ b/src/Orchard.Azure/AzureFileSystem.cs @@ -28,8 +28,8 @@ namespace Orchard.Azure { // Setup the connection to custom storage accountm, e.g. Development Storage _storageAccount = storageAccount; ContainerName = containerName; - _root = String.IsNullOrEmpty(root) || root == "/" ? String.Empty : root + "/"; - _absoluteRoot = _storageAccount.BlobEndpoint.AbsoluteUri + containerName + "/" + root + "/"; + _root = String.IsNullOrEmpty(root) ? "": root + "/"; + _absoluteRoot = _storageAccount.BlobEndpoint.AbsoluteUri + "/" + containerName + "/" + root; using ( new HttpContextWeaver() ) { @@ -40,12 +40,11 @@ namespace Orchard.Azure { Container.CreateIfNotExist(); - if (isPrivate) { - Container.SetPermissions(new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Off }); - } - else { - Container.SetPermissions(new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Container }); - } + Container.SetPermissions(isPrivate + ? new BlobContainerPermissions + {PublicAccess = BlobContainerPublicAccessType.Off} + : new BlobContainerPermissions + {PublicAccess = BlobContainerPublicAccessType.Container}); } } @@ -107,7 +106,7 @@ namespace Orchard.Azure { EnsurePathIsRelative(path); - string prefix = String.Concat(Combine(Container.Name, _root), path); + string prefix = Combine(Combine(Container.Name, _root), path); if ( !prefix.EndsWith("/") ) prefix += "/"; @@ -128,7 +127,16 @@ namespace Orchard.Azure { EnsurePathIsRelative(path); using ( new HttpContextWeaver() ) { - if ( !Container.DirectoryExists(String.Concat(_root, path)) ) { + + // return root folders + if (String.Concat(_root, path) == String.Empty) { + return Container.ListBlobs() + .OfType() + .Select(d => new AzureBlobFolderStorage(d, _absoluteRoot)) + .ToList(); + } + + if (!Container.DirectoryExists(String.Concat(_root, path)) ) { try { CreateFolder(String.Concat(_root, path)); } @@ -146,14 +154,12 @@ namespace Orchard.Azure { } } - public void TryCreateFolder(string path) - { + public void TryCreateFolder(string path) { EnsurePathIsRelative(path); CreateFile(Combine(path, FolderEntry)); } - public void CreateFolder(string path) - { + public void CreateFolder(string path) { EnsurePathIsRelative(path); using (new HttpContextWeaver()) { Container.EnsureDirectoryDoesNotExist(String.Concat(_root, path)); diff --git a/src/Orchard.Azure/Environment/Configuration/AzureShellSettingsManager.cs b/src/Orchard.Azure/Environment/Configuration/AzureShellSettingsManager.cs index 524c02777..d38e673e6 100644 --- a/src/Orchard.Azure/Environment/Configuration/AzureShellSettingsManager.cs +++ b/src/Orchard.Azure/Environment/Configuration/AzureShellSettingsManager.cs @@ -2,10 +2,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using JetBrains.Annotations; using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.ServiceRuntime; -using Microsoft.WindowsAzure.StorageClient; using Orchard.Environment.Configuration; using Orchard.Localization; @@ -13,97 +11,68 @@ namespace Orchard.Azure.Environment.Configuration { public class AzureShellSettingsManager : IShellSettingsManager { public const string ContainerName = "sites"; // container names must be lower cased + public const string SettingsFilename = "Settings.txt"; + private readonly IShellSettingsManagerEventHandler _events; + private readonly AzureFileSystem _fileSystem; - private readonly CloudStorageAccount _storageAccount; - public CloudBlobClient BlobClient { get; private set; } - public CloudBlobContainer Container { get; private set; } - - Localizer T { get; [UsedImplicitly] - set; } + Localizer T { get; set; } public AzureShellSettingsManager(IShellSettingsManagerEventHandler events) - : this(CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue("DataConnectionString")), events) - { - } + : this(CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue("DataConnectionString")), events) {} - public AzureShellSettingsManager(CloudStorageAccount storageAccount, IShellSettingsManagerEventHandler events) - { - // Setup the connection to custom storage accountm, e.g. Development Storage - _storageAccount = storageAccount; + public AzureShellSettingsManager(CloudStorageAccount storageAccount, IShellSettingsManagerEventHandler events) { _events = events; - - using ( new HttpContextWeaver() ) { - 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) - Container = new CloudBlobContainer(ContainerName, BlobClient); - Container.CreateIfNotExist(); - - // Tenant settings are protected by default - Container.SetPermissions(new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Off }); - } - + _fileSystem = new AzureFileSystem(ContainerName, String.Empty, true, storageAccount); } IEnumerable IShellSettingsManager.LoadSettings() { - return LoadSettings().ToArray(); + var settings = LoadSettings().ToArray(); + return settings; } void IShellSettingsManager.SaveSettings(ShellSettings settings) { - if ( settings == null ) - throw new ArgumentException(T("There are no settings to save.").ToString()); - - if ( string.IsNullOrEmpty(settings.Name) ) - throw new ArgumentException(T("Settings \"Name\" is not set.").ToString()); + var content = ComposeSettings(settings); + var filePath = String.Concat(settings.Name, "/", SettingsFilename); + var file = _fileSystem.CreateFile(filePath); - using ( new HttpContextWeaver() ) { - var filePath = String.Concat(settings.Name, "/", "Settings.txt"); - var blob = Container.GetBlockBlobReference(filePath); - blob.UploadText(ComposeSettings(settings)); + using (var stream = file.OpenWrite()) { + using (var writer = new StreamWriter(stream)) { + writer.Write(content); + } } _events.Saved(settings); } IEnumerable LoadSettings() { + foreach (var folder in _fileSystem.ListFolders(null)) + foreach (var file in _fileSystem.ListFiles(folder.GetPath())) { + if (!String.Equals(file.GetName(), SettingsFilename)) + continue; - using ( new HttpContextWeaver() ) { - var settingsBlobs = - BlobClient.ListBlobsWithPrefix(Container.Name + "/").OfType() - .SelectMany(directory => directory.ListBlobs()).OfType() - .Where( - blob => - string.Equals(Path.GetFileName(blob.Uri.ToString()), - "Settings.txt", - StringComparison.OrdinalIgnoreCase)); - - return settingsBlobs.Select(settingsBlob => ParseSettings(settingsBlob.DownloadText())).ToList(); - } + using (var stream = file.OpenRead()) + using (var reader = new StreamReader(stream)) + yield return ParseSettings(reader.ReadToEnd()); + } } - static ShellSettings ParseSettings(string text) - { + static ShellSettings ParseSettings(string text) { var shellSettings = new ShellSettings(); if (String.IsNullOrEmpty(text)) return shellSettings; - string[] settings = text.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); - foreach (var setting in settings) - { - string[] settingFields = setting.Split(new[] { ":" }, StringSplitOptions.RemoveEmptyEntries); + string[] settings = text.Split(new[] {"\r\n"}, StringSplitOptions.RemoveEmptyEntries); + foreach (var setting in settings) { + string[] settingFields = setting.Split(new[] {":"}, StringSplitOptions.RemoveEmptyEntries); int fieldsLength = settingFields.Length; if (fieldsLength != 2) continue; - for (int i = 0; i < fieldsLength; i++) - { + for (int i = 0; i < fieldsLength; i++) { settingFields[i] = settingFields[i].Trim(); } - if (settingFields[1] != "null") - { - switch (settingFields[0]) - { + if (settingFields[1] != "null") { + switch (settingFields[0]) { case "Name": shellSettings.Name = settingFields[1]; break; @@ -140,23 +109,22 @@ namespace Orchard.Azure.Environment.Configuration { return shellSettings; } - static string ComposeSettings(ShellSettings settings) - { + static string ComposeSettings(ShellSettings settings) { if (settings == null) return ""; return string.Format("Name: {0}\r\nDataProvider: {1}\r\nDataConnectionString: {2}\r\nDataPrefix: {3}\r\nRequestUrlHost: {4}\r\nRequestUrlPrefix: {5}\r\nState: {6}\r\nEncryptionAlgorithm: {7}\r\nEncryptionKey: {8}\r\nEncryptionIV: {9}\r\n", - settings.Name, - settings.DataProvider, - settings.DataConnectionString ?? "null", - settings.DataTablePrefix ?? "null", - settings.RequestUrlHost ?? "null", - settings.RequestUrlPrefix ?? "null", - settings.State != null ? settings.State.ToString() : String.Empty, - settings.EncryptionAlgorithm ?? "null", - settings.EncryptionKey ?? "null", - settings.EncryptionIV ?? "null" - ); + settings.Name, + settings.DataProvider, + settings.DataConnectionString ?? "null", + settings.DataTablePrefix ?? "null", + settings.RequestUrlHost ?? "null", + settings.RequestUrlPrefix ?? "null", + settings.State != null ? settings.State.ToString() : String.Empty, + settings.EncryptionAlgorithm ?? "null", + settings.EncryptionKey ?? "null", + settings.EncryptionIV ?? "null" + ); } } } diff --git a/src/Orchard.Azure/Orchard.Azure.5.0.ReSharper b/src/Orchard.Azure/Orchard.Azure.5.0.ReSharper new file mode 100644 index 000000000..470d2dcf2 --- /dev/null +++ b/src/Orchard.Azure/Orchard.Azure.5.0.ReSharper @@ -0,0 +1,108 @@ + + + + + SOLUTION + + + False + False + False + END_OF_LINE + END_OF_LINE + TOGETHER + ALWAYS_ADD + ALWAYS_ADD + ALWAYS_ADD + ALWAYS_ADD + ALWAYS_ADD + ALWAYS_ADD + END_OF_LINE + END_OF_LINE + + public + protected + internal + private + new + abstract + virtual + override + sealed + static + readonly + extern + unsafe + volatile + + END_OF_LINE + END_OF_LINE + False + + + + $object$_On$event$ + $event$Handler + + + + + + + + + + + + + + + + + + + + + + + + + $object$_On$event$ + $event$Handler + + + + + + + + + + + + + + $object$_On$event$ + $event$Handler + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Orchard.Azure/Orchard.Azure.CloudService/ServiceDefinition.csdef b/src/Orchard.Azure/Orchard.Azure.CloudService/ServiceDefinition.csdef index 462e8f2ae..62fdd5deb 100644 --- a/src/Orchard.Azure/Orchard.Azure.CloudService/ServiceDefinition.csdef +++ b/src/Orchard.Azure/Orchard.Azure.CloudService/ServiceDefinition.csdef @@ -1,6 +1,13 @@  +