Extended default ShellSettingsManager implementation to apply platform configuration overrrides when loading settings.

Removed the AzureConfigShellSettingsManager class.
This commit is contained in:
Daniel Stolt
2013-08-27 04:09:58 +02:00
committed by Sebastien Ros
parent 93c628bf85
commit 687fdadccc
8 changed files with 105 additions and 89 deletions

View File

@@ -7,9 +7,9 @@
<autofac defaultAssembly="Orchard.Framework">
<components>
<!-- Configure Orchard to store shell settings (Settings.txt) in platform configuration and Azure Blob Storage. -->
<!-- Configure Orchard to store shell settings in Windows Azure Blob Storage. -->
<component instance-scope="single-instance" type="Orchard.FileSystems.Media.ConfigurationMimeTypeProvider, Orchard.Framework" service="Orchard.FileSystems.Media.IMimeTypeProvider"></component>
<component instance-scope="single-instance" type="Orchard.Azure.Services.Environment.Configuration.AzureConfigShellSettingsManager, Orchard.Azure" service="Orchard.Environment.Configuration.IShellSettingsManager"></component>
<component instance-scope="single-instance" type="Orchard.Azure.Services.Environment.Configuration.AzureBlobShellSettingsManager, Orchard.Azure" service="Orchard.Environment.Configuration.IShellSettingsManager"></component>
</components>
</autofac>

View File

@@ -6,12 +6,6 @@
</configSections>
<autofac defaultAssembly="Orchard.Framework">
<!-- Uncomment below to have Orchard store shell settings (Settings.txt) in platform configuration and Azure Blob Storage (useful when running multiple instances on Azure Web sites). -->
<!--<components>
<component instance-scope="single-instance" type="Orchard.Azure.Services.Environment.Configuration.AzureConfigShellSettingsManager, Orchard.Azure" service="Orchard.Environment.Configuration.IShellSettingsManager"></component>
</components>-->
</autofac>
</configuration>

View File

@@ -147,7 +147,6 @@
<Compile Include="Services\Caching\Database\AzureCacheConfiguration.cs" />
<Compile Include="Services\Caching\Database\AzureCacheProvider.cs" />
<Compile Include="Services\Caching\Output\AzureOutputCacheStorageProvider.cs" />
<Compile Include="Services\Environment\Configuration\AzureConfigShellSettingsManager.cs" />
<Compile Include="Services\Environment\Configuration\AzureBlobShellSettingsManager.cs" />
<Compile Include="Services\FileSystems\AzureFileSystem.cs" />
<Compile Include="Services\FileSystems\CloudBlobContainerExtensions.cs" />

View File

@@ -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 {
/// <summary>
/// Provides an IShellSettingsManager implementation that uses Windows Azure Blob Storage as the
/// underlying storage system.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
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<ShellSettings> 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<ShellSettings> LoadSettingsInternal() {
foreach (var folder in FileSystem.ListFolders(null)) {
foreach (var file in FileSystem.ListFiles(folder.GetPath())) {

View File

@@ -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<ShellSettings> 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;
}
}
}

View File

@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.WindowsAzure;
namespace Orchard.Environment.Configuration {
/// <summary>
/// Provides logic to override individual shell settings with values read from platform configuration.
/// </summary>
/// <remarks>
/// 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 <see cref="Microsoft.WindowsAzure.CloudConfigurationManager"/> class looks.
/// </remarks>
public static class PlatformShellSettings {
private const string _prefix = "Orchard";
private const string _emptyValueString = "null";
/// <summary>
/// Applies platform configuration overrides to the specified ShellSettings objects.
/// </summary>
/// <param name="shellSettingsList">A list of ShellSettings objects to which platform configuration overrides will be applied.</param>
public static void ApplyTo(IEnumerable<ShellSettings> 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;
}
}
}

View File

@@ -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<ShellSettings> 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<ShellSettings> LoadSettings() {
private IEnumerable<ShellSettings> 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));

View File

@@ -84,6 +84,10 @@
<HintPath>..\..\lib\log4net\log4net.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.WindowsAzure.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\windowsazure\Microsoft.WindowsAzure.Configuration.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>..\..\lib\newtonsoft.json\Newtonsoft.Json.dll</HintPath>
</Reference>
@@ -218,6 +222,7 @@
<Compile Include="Environment\AutofacUtil\ConfigurationSettingsReaderConstants.cs" />
<Compile Include="Environment\CollectionOrderModule.cs" />
<Compile Include="Caching\DefaultAsyncTokenProvider.cs" />
<Compile Include="Environment\Configuration\PlatformShellSettings.cs" />
<Compile Include="Environment\Configuration\ShellSettingsSerializer.cs" />
<Compile Include="Environment\Extensions\DefaultCriticalErrorProvider.cs" />
<Compile Include="Environment\Extensions\ExtensionMonitoringCoordinator.cs" />