From c34812c78b8cb007cdeb9f2b2db12a25358d5962 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Tue, 15 Jun 2010 17:27:43 -0700 Subject: [PATCH] Added HttpContextWeaver class --HG-- branch : dev --- src/Orchard.Azure/AzureFileSystem.cs | 189 +++++---- src/Orchard.Azure/AzureHelper.cs | 33 -- .../CloudBlobContainerExtensions.cs | 11 +- .../AzureShellSettingsManager.cs | 65 ++- .../FileSystems/AppData/AzureAppDataFolder.cs | 22 +- src/Orchard.Azure/HttpContextWeaver.cs | 28 ++ .../Orchard.Azure.CloudService.sln | 6 + .../ServiceConfiguration.cscfg | 15 - .../ServiceDefinition.csdef | 9 - .../Orchard.Azure.Web.csproj | 399 +++++++++++++++++- src/Orchard.Azure/Orchard.Azure.csproj | 2 +- 11 files changed, 581 insertions(+), 198 deletions(-) delete mode 100644 src/Orchard.Azure/AzureHelper.cs create mode 100644 src/Orchard.Azure/HttpContextWeaver.cs diff --git a/src/Orchard.Azure/AzureFileSystem.cs b/src/Orchard.Azure/AzureFileSystem.cs index d58b85c4e..e34a00535 100644 --- a/src/Orchard.Azure/AzureFileSystem.cs +++ b/src/Orchard.Azure/AzureFileSystem.cs @@ -27,37 +27,23 @@ namespace Orchard.Azure { ContainerName = containerName; _root = String.IsNullOrEmpty(root) || root == "/" ? String.Empty : root + "/"; - AzureHelper.InjectHttpContext(() - => - { + 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 = BlobClient.GetContainerReference(ContainerName); + 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 = BlobClient.GetContainerReference(ContainerName); - Container.CreateIfNotExist(); + Container.CreateIfNotExist(); + + if (isPrivate) { + Container.SetPermissions(new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Off }); + } + else { + Container.SetPermissions(new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Container }); + } + } - if (isPrivate) - { - Container.SetPermissions(new BlobContainerPermissions - { - PublicAccess = - BlobContainerPublicAccessType - .Off - }); - } - else - { - Container.SetPermissions(new BlobContainerPermissions - { - PublicAccess = - BlobContainerPublicAccessType - .Container - }); - } - }); - } private static void EnsurePathIsRelative(string path) { @@ -68,13 +54,20 @@ namespace Orchard.Azure { public IStorageFile GetFile(string path) { EnsurePathIsRelative(path); path = String.Concat(_root, path); - Container.EnsureBlobExists(path); - return new AzureBlobFileStorage(Container.GetBlockBlobReference(path)); + + using ( new HttpContextWeaver() ) + { + Container.EnsureBlobExists(path); + return new AzureBlobFileStorage(Container.GetBlockBlobReference(path)); + } } public bool FileExists(string path) { - path = String.Concat(_root, path); - return Container.BlobExists(path); + using ( new HttpContextWeaver() ) + { + path = String.Concat(_root, path); + return Container.BlobExists(path); + } } public IEnumerable ListFiles(string path) { @@ -83,51 +76,67 @@ namespace Orchard.Azure { string prefix = String.Concat(Container.Name, "/", _root, path); if ( !prefix.EndsWith("/") ) prefix += "/"; - - foreach ( var blobItem in BlobClient.ListBlobsWithPrefix(prefix).OfType() ) { - yield return new AzureBlobFileStorage(blobItem); + using ( new HttpContextWeaver() ) + { + foreach (var blobItem in BlobClient.ListBlobsWithPrefix(prefix).OfType()) + { + yield return new AzureBlobFileStorage(blobItem); + } } } public IEnumerable ListFolders(string path) { EnsurePathIsRelative(path); path = String.Concat(_root, path); + using ( new HttpContextWeaver() ) + { + if (!Container.DirectoryExists(path)) + { + try + { + CreateFolder(path); + } + catch (Exception ex) + { + throw new ArgumentException(string.Format("The folder could not be created at path: {0}. {1}", + path, ex)); + } + } - if ( !Container.DirectoryExists(path) ) { - try { - CreateFolder(path); - } - catch ( Exception ex ) { - throw new ArgumentException(string.Format("The folder could not be created at path: {0}. {1}", path, ex)); - } + return Container.GetDirectoryReference(path) + .ListBlobs() + .OfType() + .Select(d => new AzureBlobFolderStorage(d)) + .ToList(); } - - return Container.GetDirectoryReference(path) - .ListBlobs() - .OfType() - .Select(d => new AzureBlobFolderStorage(d)) - .ToList(); } - public void CreateFolder(string path) { + public void CreateFolder(string path) + { EnsurePathIsRelative(path); path = String.Concat(_root, path); - - Container.EnsureDirectoryDoesNotExist(path); - Container.GetDirectoryReference(path); + using (new HttpContextWeaver()) + { + Container.EnsureDirectoryDoesNotExist(path); + Container.GetDirectoryReference(path); + } } public void DeleteFolder(string path) { EnsurePathIsRelative(path); path = String.Concat(_root, path); - Container.EnsureDirectoryExists(path); - foreach ( var blob in Container.GetDirectoryReference(path).ListBlobs() ) { - if ( blob is CloudBlob ) - ( (CloudBlob)blob ).Delete(); + using ( new HttpContextWeaver() ) + { + Container.EnsureDirectoryExists(path); + foreach (var blob in Container.GetDirectoryReference(path).ListBlobs()) + { + if (blob is CloudBlob) + ((CloudBlob) blob).Delete(); - if ( blob is CloudBlobDirectory ) - DeleteFolder(blob.Uri.ToString().Substring(Container.Uri.ToString().Length + 1 + _root.Length)); + if (blob is CloudBlobDirectory) + DeleteFolder(blob.Uri.ToString().Substring(Container.Uri.ToString().Length + 1 + _root.Length)); + } } } @@ -141,32 +150,39 @@ namespace Orchard.Azure { if ( !newPath.EndsWith("/") ) newPath += "/"; + using ( new HttpContextWeaver() ) + { + foreach (var blob in Container.GetDirectoryReference(_root + path).ListBlobs()) + { + 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); + } - foreach ( var blob in Container.GetDirectoryReference(_root + path).ListBlobs() ) { - 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); + 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) { EnsurePathIsRelative(path); path = String.Concat(_root, path); - Container.EnsureBlobExists(path); - var blob = Container.GetBlockBlobReference(path); - blob.Delete(); + using ( new HttpContextWeaver() ) + { + Container.EnsureBlobExists(path); + var blob = Container.GetBlockBlobReference(path); + blob.Delete(); + } } public void RenameFile(string path, string newPath) { @@ -175,14 +191,16 @@ namespace Orchard.Azure { EnsurePathIsRelative(newPath); newPath = String.Concat(_root, newPath); + using ( new HttpContextWeaver() ) + { + Container.EnsureBlobExists(path); + Container.EnsureBlobDoesNotExist(newPath); - Container.EnsureBlobExists(path); - Container.EnsureBlobDoesNotExist(newPath); - - var blob = Container.GetBlockBlobReference(path); - var newBlob = Container.GetBlockBlobReference(newPath); - newBlob.CopyFromBlob(blob); - blob.Delete(); + var blob = Container.GetBlockBlobReference(path); + var newBlob = Container.GetBlockBlobReference(newPath); + newBlob.CopyFromBlob(blob); + blob.Delete(); + } } public IStorageFile CreateFile(string path) { @@ -201,8 +219,11 @@ namespace Orchard.Azure { public string GetPublicUrl(string path) { EnsurePathIsRelative(path); path = String.Concat(_root, path); - Container.EnsureBlobExists(path); - return Container.GetBlockBlobReference(path).Uri.ToString(); + using ( new HttpContextWeaver() ) + { + Container.EnsureBlobExists(path); + return Container.GetBlockBlobReference(path).Uri.ToString(); + } } private class AzureBlobFileStorage : IStorageFile { diff --git a/src/Orchard.Azure/AzureHelper.cs b/src/Orchard.Azure/AzureHelper.cs deleted file mode 100644 index 69a4dcde5..000000000 --- a/src/Orchard.Azure/AzureHelper.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Web; -using System.IO; - -namespace Orchard.Azure { - public class AzureHelper { - public static void InjectHttpContext(Action action) { - if(HttpContext.Current == null ) - { - action(); - return; - } - - var currentContext = HttpContext.Current; - try { - // THIS IS A HACK - // There is a bug in ASP.NET 4.0 in HttpEncoder.Current, which prevents some calls to HttpUtiliy.Decode/Encode - // from Application_Start, on IIS or Azure. This hack will be removed when the bug is corrected. - // This is fired by the assembly Microsoft.WindowsAzure.StorageClient. Should be corrected in .NET4 SP1 - - HttpContext.Current = new HttpContext(new HttpRequest(String.Empty, "http://localhost", String.Empty), new HttpResponse(new StringWriter())); - - action(); - } - finally { - HttpContext.Current = currentContext; - } - } - } -} diff --git a/src/Orchard.Azure/CloudBlobContainerExtensions.cs b/src/Orchard.Azure/CloudBlobContainerExtensions.cs index 34ca9d9a3..d88902659 100644 --- a/src/Orchard.Azure/CloudBlobContainerExtensions.cs +++ b/src/Orchard.Azure/CloudBlobContainerExtensions.cs @@ -11,12 +11,11 @@ namespace Orchard.Azure { throw new ArgumentException("Path can't be empty"); try { - AzureHelper.InjectHttpContext( - () => - { - var blob = container.GetBlockBlobReference(path); - blob.FetchAttributes(); - }); + using ( new HttpContextWeaver() ) + { + var blob = container.GetBlockBlobReference(path); + blob.FetchAttributes(); + } return true; } catch ( StorageClientException e ) { diff --git a/src/Orchard.Azure/Environment/Configuration/AzureShellSettingsManager.cs b/src/Orchard.Azure/Environment/Configuration/AzureShellSettingsManager.cs index abca8cb9b..dfdef5d78 100644 --- a/src/Orchard.Azure/Environment/Configuration/AzureShellSettingsManager.cs +++ b/src/Orchard.Azure/Environment/Configuration/AzureShellSettingsManager.cs @@ -35,23 +35,18 @@ namespace Orchard.Azure.Environment.Configuration { _storageAccount = storageAccount; _events = events; - AzureHelper.InjectHttpContext(() => - { - BlobClient = _storageAccount.CreateCloudBlobClient(); + 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(); + // 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 }); + } - // Tenant settings are protected by default - Container.SetPermissions(new BlobContainerPermissions - { - PublicAccess = - BlobContainerPublicAccessType.Off - }); - }); - } IEnumerable IShellSettingsManager.LoadSettings() { @@ -65,37 +60,29 @@ namespace Orchard.Azure.Environment.Configuration { if ( string.IsNullOrEmpty(settings.Name) ) throw new ArgumentException(T("Settings \"Name\" is not set.").ToString()); - AzureHelper.InjectHttpContext( - () => - { - var filePath = String.Concat(settings.Name, "/", "Settings.txt"); - var blob = Container.GetBlockBlobReference(filePath); - blob.UploadText(ComposeSettings(settings)); - }); + using ( new HttpContextWeaver() ) { + var filePath = String.Concat(settings.Name, "/", "Settings.txt"); + var blob = Container.GetBlockBlobReference(filePath); + blob.UploadText(ComposeSettings(settings)); + } _events.Saved(settings); } IEnumerable LoadSettings() { - var result = new List(); + 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)); - AzureHelper.InjectHttpContext( - () => - { - 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)); - - result.AddRange(settingsBlobs.Select(settingsBlob => ParseSettings(settingsBlob.DownloadText()))); - }); - - return result; + return settingsBlobs.Select(settingsBlob => ParseSettings(settingsBlob.DownloadText())).ToList(); + } } class Content { diff --git a/src/Orchard.Azure/FileSystems/AppData/AzureAppDataFolder.cs b/src/Orchard.Azure/FileSystems/AppData/AzureAppDataFolder.cs index ee4a5b190..d233b68d6 100644 --- a/src/Orchard.Azure/FileSystems/AppData/AzureAppDataFolder.cs +++ b/src/Orchard.Azure/FileSystems/AppData/AzureAppDataFolder.cs @@ -15,21 +15,25 @@ namespace Orchard.Azure.FileSystems.AppData { } public void CreateFile(string path, string content) { - if(_fs.FileExists(path)) { - DeleteFile(path); - } + using ( new HttpContextWeaver() ) { + if (_fs.FileExists(path)) { + DeleteFile(path); + } - using (var stream = _fs.CreateFile(path).OpenWrite()) { - using(var writer = new StreamWriter(stream)) { - writer.Write(content); + using (var stream = _fs.CreateFile(path).OpenWrite()) { + using (var writer = new StreamWriter(stream)) { + writer.Write(content); + } } } } public string ReadFile(string path) { - using ( var stream = _fs.GetFile(path).OpenRead() ) { - using ( var reader = new StreamReader(stream) ) { - return reader.ReadToEnd(); + using ( new HttpContextWeaver() ) { + using (var stream = _fs.GetFile(path).OpenRead()) { + using (var reader = new StreamReader(stream)) { + return reader.ReadToEnd(); + } } } } diff --git a/src/Orchard.Azure/HttpContextWeaver.cs b/src/Orchard.Azure/HttpContextWeaver.cs new file mode 100644 index 000000000..0203e5793 --- /dev/null +++ b/src/Orchard.Azure/HttpContextWeaver.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web; +using System.IO; + +namespace Orchard.Azure { + /// + /// THIS IS A HACK + /// There is a bug in ASP.NET 4.0 in HttpEncoder.Current, which prevents some calls to HttpUtiliy.Decode/Encode + /// from Application_Start, on IIS or Azure. This hack will be removed when the bug is corrected. + /// This is fired by the assembly Microsoft.WindowsAzure.StorageClient. Should be corrected in .NET4 SP1 + /// + public class HttpContextWeaver : IDisposable { + private readonly HttpContext _current; + + public HttpContextWeaver() + { + _current = HttpContext.Current; + HttpContext.Current = new HttpContext(new HttpRequest(String.Empty, "http://localhost", String.Empty), new HttpResponse(new StringWriter())); + } + + public void Dispose() { + HttpContext.Current = _current; + } + } +} diff --git a/src/Orchard.Azure/Orchard.Azure.CloudService.sln b/src/Orchard.Azure/Orchard.Azure.CloudService.sln index 61c96e1e5..b44486312 100644 --- a/src/Orchard.Azure/Orchard.Azure.CloudService.sln +++ b/src/Orchard.Azure/Orchard.Azure.CloudService.sln @@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Azure", "Orchard.Az EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Framework", "..\Orchard\Orchard.Framework.csproj", "{2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Core", "..\Orchard.Web\Core\Orchard.Core.csproj", "{9916839C-39FC-4CEB-A5AF-89CA7E87119F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -31,6 +33,10 @@ Global {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6}.Debug|Any CPU.Build.0 = Debug|Any CPU {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6}.Release|Any CPU.ActiveCfg = Release|Any CPU {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6}.Release|Any CPU.Build.0 = Release|Any CPU + {9916839C-39FC-4CEB-A5AF-89CA7E87119F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9916839C-39FC-4CEB-A5AF-89CA7E87119F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9916839C-39FC-4CEB-A5AF-89CA7E87119F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9916839C-39FC-4CEB-A5AF-89CA7E87119F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Orchard.Azure/Orchard.Azure.CloudService/ServiceConfiguration.cscfg b/src/Orchard.Azure/Orchard.Azure.CloudService/ServiceConfiguration.cscfg index 7e0691f74..5fd08b040 100644 --- a/src/Orchard.Azure/Orchard.Azure.CloudService/ServiceConfiguration.cscfg +++ b/src/Orchard.Azure/Orchard.Azure.CloudService/ServiceConfiguration.cscfg @@ -1,18 +1,3 @@ - - - - - - - - - - - - \ 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 7fccedb76..8d96b8830 100644 --- a/src/Orchard.Azure/Orchard.Azure.CloudService/ServiceDefinition.csdef +++ b/src/Orchard.Azure/Orchard.Azure.CloudService/ServiceDefinition.csdef @@ -1,12 +1,3 @@  - - - - - - - - - \ No newline at end of file diff --git a/src/Orchard.Azure/Orchard.Azure.Web/Orchard.Azure.Web.csproj b/src/Orchard.Azure/Orchard.Azure.Web/Orchard.Azure.Web.csproj index ab6d7c41c..2517da264 100644 --- a/src/Orchard.Azure/Orchard.Azure.Web/Orchard.Azure.Web.csproj +++ b/src/Orchard.Azure/Orchard.Azure.Web/Orchard.Azure.Web.csproj @@ -92,29 +92,424 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + Designer + + + {9916839C-39FC-4CEB-A5AF-89CA7E87119F} + Orchard.Core + {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework + False {2505AA84-65A6-43D0-9C27-4F44FD576284} Orchard.Azure - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +