diff --git a/src/Orchard.Azure/Orchard.Azure.Web/Config/Host.config b/src/Orchard.Azure/Orchard.Azure.Web/Config/Host.config index 4b8b809f6..008324024 100644 --- a/src/Orchard.Azure/Orchard.Azure.Web/Config/Host.config +++ b/src/Orchard.Azure/Orchard.Azure.Web/Config/Host.config @@ -7,9 +7,9 @@ - + - + diff --git a/src/Orchard.Web/Config/Host.config b/src/Orchard.Web/Config/Host.config index abf7158a9..a4f3ea12d 100644 --- a/src/Orchard.Web/Config/Host.config +++ b/src/Orchard.Web/Config/Host.config @@ -6,12 +6,6 @@ - - - - \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Azure/Orchard.Azure.csproj b/src/Orchard.Web/Modules/Orchard.Azure/Orchard.Azure.csproj index a62a42d22..b0f473752 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure/Orchard.Azure.csproj +++ b/src/Orchard.Web/Modules/Orchard.Azure/Orchard.Azure.csproj @@ -147,7 +147,6 @@ - diff --git a/src/Orchard.Web/Modules/Orchard.Azure/Services/Environment/Configuration/AzureBlobShellSettingsManager.cs b/src/Orchard.Web/Modules/Orchard.Azure/Services/Environment/Configuration/AzureBlobShellSettingsManager.cs index 2110f4fda..774d0ef57 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure/Services/Environment/Configuration/AzureBlobShellSettingsManager.cs +++ b/src/Orchard.Web/Modules/Orchard.Azure/Services/Environment/Configuration/AzureBlobShellSettingsManager.cs @@ -3,26 +3,40 @@ using System.Collections.Generic; using System.IO; using System.Linq; using Microsoft.WindowsAzure; -using Microsoft.WindowsAzure.Storage; +using Microsoft.WindowsAzure.ServiceRuntime; using Orchard.Azure.Services.FileSystems; using Orchard.Environment.Configuration; using Orchard.FileSystems.Media; +using Orchard.Logging; namespace Orchard.Azure.Services.Environment.Configuration { + /// + /// Provides an IShellSettingsManager implementation that uses Windows Azure Blob Storage as the + /// underlying storage system. + /// + /// + /// Additionally, this class handles role configuration change events when running in a Windows Azure Cloud + /// Service to ensure all Orchard tenents are notified whenever a role configuration setting is changed + /// through the management portal or API. + /// public class AzureBlobShellSettingsManager : Component, IShellSettingsManager { - protected const string EmptyValueString = "null"; protected readonly IShellSettingsManagerEventHandler Events; protected readonly AzureFileSystem FileSystem; public AzureBlobShellSettingsManager(IShellSettingsManagerEventHandler events, IMimeTypeProvider mimeTypeProvider) { Events = events; FileSystem = new AzureFileSystem(CloudConfigurationManager.GetSetting(Constants.ShellSettingsStorageConnectionStringSettingName), Constants.ShellSettingsContainerName, String.Empty, true, mimeTypeProvider); + if (RoleEnvironment.IsAvailable) { + RoleEnvironment.Changing += RoleEnvironment_Changing; + RoleEnvironment.Changed += RoleEnvironment_Changed; + } } public virtual IEnumerable LoadSettings() { var settings = LoadSettingsInternal().ToArray(); + PlatformShellSettings.ApplyTo(settings); // Apply platform configuration overrides. return settings; } @@ -40,6 +54,28 @@ namespace Orchard.Azure.Services.Environment.Configuration { Events.Saved(settings); } + void RoleEnvironment_Changing(object sender, RoleEnvironmentChangingEventArgs e) { + // Indicate to the fabric controller that we can handle any changes. + e.Cancel = false; + } + + private void RoleEnvironment_Changed(object sender, RoleEnvironmentChangedEventArgs e) { + Logger.Debug("Handling RoleEnvironmentChanged event."); + + var configurationChangeQuery = + from c in e.Changes + where c is RoleEnvironmentConfigurationSettingChange + select c; + + // If there's a configuration settings change, inform all Orchard tenants. + if (configurationChangeQuery.Any()) { + Logger.Information("Role configuration settings changed; refreshing Orchard shell settings."); + var settingsList = LoadSettings(); + foreach (var settings in settingsList) + Events.Saved(settings); + } + } + private IEnumerable LoadSettingsInternal() { foreach (var folder in FileSystem.ListFolders(null)) { foreach (var file in FileSystem.ListFiles(folder.GetPath())) { diff --git a/src/Orchard.Web/Modules/Orchard.Azure/Services/Environment/Configuration/AzureConfigShellSettingsManager.cs b/src/Orchard.Web/Modules/Orchard.Azure/Services/Environment/Configuration/AzureConfigShellSettingsManager.cs deleted file mode 100644 index 725bd2a89..000000000 --- a/src/Orchard.Web/Modules/Orchard.Azure/Services/Environment/Configuration/AzureConfigShellSettingsManager.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.WindowsAzure; -using Microsoft.WindowsAzure.ServiceRuntime; -using Microsoft.WindowsAzure.Storage; -using Orchard.Environment.Configuration; -using Orchard.FileSystems.Media; -using Orchard.Logging; - -namespace Orchard.Azure.Services.Environment.Configuration { - - public class AzureConfigShellSettingsManager : AzureBlobShellSettingsManager { - - private const string _prefix = "Orchard"; - - public AzureConfigShellSettingsManager(IShellSettingsManagerEventHandler events, IMimeTypeProvider mimeTypeProvider) - : base(events, mimeTypeProvider) { - if (RoleEnvironment.IsAvailable) { - RoleEnvironment.Changing += RoleEnvironment_Changing; - RoleEnvironment.Changed += RoleEnvironment_Changed; - } - } - - public override IEnumerable LoadSettings() { - var settingsList = base.LoadSettings(); - - foreach (var settings in settingsList) { - foreach (var key in settings.Keys.ToArray()) { - var cloudConfigurationKey = String.Format("{0}.{1}.{2}", _prefix, settings.Name, key); - var cloudConfigurationValue = ParseValue(CloudConfigurationManager.GetSetting(cloudConfigurationKey)); - if (cloudConfigurationValue != null) - settings[key] = cloudConfigurationValue; - } - } - - return settingsList; - } - - void RoleEnvironment_Changing(object sender, RoleEnvironmentChangingEventArgs e) { - // Indicate to the fabric controller that we can handle any changes. - e.Cancel = false; - } - - private void RoleEnvironment_Changed(object sender, RoleEnvironmentChangedEventArgs e) { - Logger.Debug("Handling RoleEnvironmentChanged event."); - - var configurationChangeQuery = - from c in e.Changes - where c is RoleEnvironmentConfigurationSettingChange - select c; - - // If there's a configuration settings change, inform all Orchard tenants. - if (configurationChangeQuery.Any()) { - Logger.Information("Role configuration settings changed; refreshing Orchard shell settings."); - var settingsList = LoadSettings(); - foreach (var settings in settingsList) - Events.Saved(settings); - } - } - - private string ParseValue(string value) { - if (value == EmptyValueString || String.IsNullOrWhiteSpace(value)) - return null; - return value; - } - } -} diff --git a/src/Orchard/Environment/Configuration/PlatformShellSettings.cs b/src/Orchard/Environment/Configuration/PlatformShellSettings.cs new file mode 100644 index 000000000..00f4ec345 --- /dev/null +++ b/src/Orchard/Environment/Configuration/PlatformShellSettings.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.WindowsAzure; + +namespace Orchard.Environment.Configuration { + + /// + /// Provides logic to override individual shell settings with values read from platform configuration. + /// + /// + /// This class is used by IShellSettingsManager implementations to apply overrides of individual + /// shell settings from corresponding values in platform configuration. For each setting found + /// in the shell settings, this class looks for a corresponding platform setting named + /// Orchard.TenantName.SettingName in platform configuration. Platform configuration refers to + /// anywhere the class looks. + /// + public static class PlatformShellSettings { + + private const string _prefix = "Orchard"; + private const string _emptyValueString = "null"; + + /// + /// Applies platform configuration overrides to the specified ShellSettings objects. + /// + /// A list of ShellSettings objects to which platform configuration overrides will be applied. + public static void ApplyTo(IEnumerable shellSettingsList) { + foreach (var settings in shellSettingsList) { + foreach (var key in settings.Keys.ToArray()) { + var cloudConfigurationKey = String.Format("{0}.{1}.{2}", _prefix, settings.Name, key); + var cloudConfigurationValue = ParseValue(CloudConfigurationManager.GetSetting(cloudConfigurationKey)); + if (cloudConfigurationValue != null) + settings[key] = cloudConfigurationValue; + } + } + } + + private static string ParseValue(string value) { + if (value == _emptyValueString || String.IsNullOrWhiteSpace(value)) + return null; + return value; + } + } +} diff --git a/src/Orchard/Environment/Configuration/ShellSettingsManager.cs b/src/Orchard/Environment/Configuration/ShellSettingsManager.cs index f9ef0fe3c..d44c60e66 100644 --- a/src/Orchard/Environment/Configuration/ShellSettingsManager.cs +++ b/src/Orchard/Environment/Configuration/ShellSettingsManager.cs @@ -7,13 +7,17 @@ using Orchard.Localization; namespace Orchard.Environment.Configuration { public class ShellSettingsManager : IShellSettingsManager { + private const string _settingsFileName = "Settings.txt"; private readonly IAppDataFolder _appDataFolder; private readonly IShellSettingsManagerEventHandler _events; - public Localizer T { get; set; } - + public Localizer T { + get; + set; + } + public ShellSettingsManager( - IAppDataFolder appDataFolder, + IAppDataFolder appDataFolder, IShellSettingsManagerEventHandler events) { _appDataFolder = appDataFolder; _events = events; @@ -22,25 +26,27 @@ namespace Orchard.Environment.Configuration { } IEnumerable IShellSettingsManager.LoadSettings() { - return LoadSettings().ToArray(); + var settings = LoadSettingsInternal().ToArray(); + PlatformShellSettings.ApplyTo(settings); // Apply platform configuration overrides. + 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()); + throw new ArgumentNullException("settings"); + if (String.IsNullOrEmpty(settings.Name)) + throw new ArgumentException("The Name property of the supplied ShellSettings object is null or empty. The settings cannot be saved.", "settings"); - var filePath = Path.Combine(Path.Combine("Sites", settings.Name), "Settings.txt"); + var filePath = Path.Combine(Path.Combine("Sites", settings.Name), _settingsFileName); _appDataFolder.CreateFile(filePath, ShellSettingsSerializer.ComposeSettings(settings)); _events.Saved(settings); } - IEnumerable LoadSettings() { + private IEnumerable LoadSettingsInternal() { var filePaths = _appDataFolder .ListDirectories("Sites") .SelectMany(path => _appDataFolder.ListFiles(path)) - .Where(path => string.Equals(Path.GetFileName(path), "Settings.txt", StringComparison.OrdinalIgnoreCase)); + .Where(path => String.Equals(Path.GetFileName(path), _settingsFileName, StringComparison.OrdinalIgnoreCase)); foreach (var filePath in filePaths) { yield return ShellSettingsSerializer.ParseSettings(_appDataFolder.ReadFile(filePath)); diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index fa0446aa1..25887539c 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -84,6 +84,10 @@ ..\..\lib\log4net\log4net.dll + + False + ..\..\lib\windowsazure\Microsoft.WindowsAzure.Configuration.dll + ..\..\lib\newtonsoft.json\Newtonsoft.Json.dll @@ -218,6 +222,7 @@ +