Modified all providers in Orchard.Azure to read their settings from platform configuration.

Added clear exceptions in provider constructors when settings are missing or invalid.
Refactored cache client configuration and creation into separate class.
This commit is contained in:
Daniel Stolt 2013-08-28 21:46:14 +02:00 committed by Sebastien Ros
parent 4f354898b9
commit db85911c2f
11 changed files with 251 additions and 240 deletions

View File

@ -1,15 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<ServiceConfiguration serviceName="OrchardCloudService" osFamily="3" osVersion="*" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" schemaVersion="2013-03.2.0">
<Role name="Orchard.Azure.Web">
<Instances count="1" />
<ConfigurationSettings>
<Setting name="Orchard.Media.StorageConnectionString" value="UseDevelopmentStorage=true" />
<Setting name="Orchard.Settings.StorageConnectionString" value="UseDevelopmentStorage=true" />
<Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="UseDevelopmentStorage=true" />
<Setting name="Microsoft.WindowsAzure.Plugins.Caching.NamedCaches" value="{&quot;caches&quot;:[{&quot;name&quot;:&quot;default&quot;,&quot;policy&quot;:{&quot;eviction&quot;:{&quot;type&quot;:0},&quot;expiration&quot;:{&quot;defaultTTL&quot;:10,&quot;isExpirable&quot;:true,&quot;type&quot;:1},&quot;serverNotification&quot;:{&quot;isEnabled&quot;:false}},&quot;secondaries&quot;:0},{&quot;name&quot;:&quot;SessionStateCache&quot;,&quot;policy&quot;:{&quot;eviction&quot;:{&quot;type&quot;:0},&quot;expiration&quot;:{&quot;defaultTTL&quot;:60,&quot;isExpirable&quot;:true,&quot;type&quot;:2},&quot;serverNotification&quot;:{&quot;isEnabled&quot;:false}},&quot;secondaries&quot;:0},{&quot;name&quot;:&quot;OutputCache&quot;,&quot;policy&quot;:{&quot;eviction&quot;:{&quot;type&quot;:0},&quot;expiration&quot;:{&quot;defaultTTL&quot;:5,&quot;isExpirable&quot;:true,&quot;type&quot;:1},&quot;serverNotification&quot;:{&quot;isEnabled&quot;:false}},&quot;secondaries&quot;:0},{&quot;name&quot;:&quot;DatabaseCache&quot;,&quot;policy&quot;:{&quot;eviction&quot;:{&quot;type&quot;:0},&quot;expiration&quot;:{&quot;defaultTTL&quot;:5,&quot;isExpirable&quot;:true,&quot;type&quot;:1},&quot;serverNotification&quot;:{&quot;isEnabled&quot;:false}},&quot;secondaries&quot;:0}]}" />
<Setting name="Microsoft.WindowsAzure.Plugins.Caching.DiagnosticLevel" value="1" />
<Setting name="Microsoft.WindowsAzure.Plugins.Caching.CacheSizePercentage" value="30" />
<Setting name="Microsoft.WindowsAzure.Plugins.Caching.ConfigStoreConnectionString" value="UseDevelopmentStorage=true" />
</ConfigurationSettings>
</Role>
<Role name="Orchard.Azure.Web">
<Instances count="1" />
<ConfigurationSettings>
<Setting name="Orchard.Azure.Media.StorageConnectionString" value="UseDevelopmentStorage=true" />
<Setting name="Orchard.Azure.Settings.StorageConnectionString" value="UseDevelopmentStorage=true" />
<Setting name="Orchard.Azure.OutputCache.HostIdentifier" value="Orchard.Azure.Web" />
<Setting name="Orchard.Azure.OutputCache.CacheName" value="OutputCache" />
<Setting name="Orchard.Azure.OutputCache.Hostname" value="" />
<Setting name="Orchard.Azure.OutputCache.Port" value="" />
<Setting name="Orchard.Azure.OutputCache.AuthorizationToken" value="" />
<Setting name="Orchard.Azure.OutputCache.IsSharedCaching" value="false" />
<Setting name="Orchard.Azure.DatabaseCache.HostIdentifier" value="Orchard.Azure.Web" />
<Setting name="Orchard.Azure.DatabaseCache.CacheName" value="DatabaseCache" />
<Setting name="Orchard.Azure.DatabaseCache.Hostname" value="" />
<Setting name="Orchard.Azure.DatabaseCache.Port" value="" />
<Setting name="Orchard.Azure.DatabaseCache.AuthorizationToken" value="" />
<Setting name="Orchard.Azure.DatabaseCache.IsSharedCaching" value="false" />
<Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="UseDevelopmentStorage=true" />
<Setting name="Microsoft.WindowsAzure.Plugins.Caching.NamedCaches" value="{&quot;caches&quot;:[{&quot;name&quot;:&quot;default&quot;,&quot;policy&quot;:{&quot;eviction&quot;:{&quot;type&quot;:0},&quot;expiration&quot;:{&quot;defaultTTL&quot;:10,&quot;isExpirable&quot;:true,&quot;type&quot;:1},&quot;serverNotification&quot;:{&quot;isEnabled&quot;:false}},&quot;secondaries&quot;:0},{&quot;name&quot;:&quot;SessionStateCache&quot;,&quot;policy&quot;:{&quot;eviction&quot;:{&quot;type&quot;:0},&quot;expiration&quot;:{&quot;defaultTTL&quot;:60,&quot;isExpirable&quot;:true,&quot;type&quot;:2},&quot;serverNotification&quot;:{&quot;isEnabled&quot;:false}},&quot;secondaries&quot;:0},{&quot;name&quot;:&quot;OutputCache&quot;,&quot;policy&quot;:{&quot;eviction&quot;:{&quot;type&quot;:0},&quot;expiration&quot;:{&quot;defaultTTL&quot;:5,&quot;isExpirable&quot;:true,&quot;type&quot;:1},&quot;serverNotification&quot;:{&quot;isEnabled&quot;:false}},&quot;secondaries&quot;:0},{&quot;name&quot;:&quot;DatabaseCache&quot;,&quot;policy&quot;:{&quot;eviction&quot;:{&quot;type&quot;:0},&quot;expiration&quot;:{&quot;defaultTTL&quot;:5,&quot;isExpirable&quot;:true,&quot;type&quot;:1},&quot;serverNotification&quot;:{&quot;isEnabled&quot;:false}},&quot;secondaries&quot;:0}]}" />
<Setting name="Microsoft.WindowsAzure.Plugins.Caching.DiagnosticLevel" value="1" />
<Setting name="Microsoft.WindowsAzure.Plugins.Caching.CacheSizePercentage" value="30" />
<Setting name="Microsoft.WindowsAzure.Plugins.Caching.ConfigStoreConnectionString" value="UseDevelopmentStorage=true" />
</ConfigurationSettings>
</Role>
</ServiceConfiguration>

View File

@ -1,37 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="OrchardCloudService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2013-03.2.0">
<WebRole name="Orchard.Azure.Web">
<Sites>
<Site name="Web">
<Bindings>
<Binding name="HttpIn" endpointName="HttpIn" />
</Bindings>
</Site>
</Sites>
<Imports>
<Import moduleName="Diagnostics" />
<Import moduleName="Caching" />
</Imports>
<ConfigurationSettings>
<Setting name="Orchard.Settings.StorageConnectionString" />
<Setting name="Orchard.Media.StorageConnectionString" />
</ConfigurationSettings>
<Endpoints>
<InputEndpoint name="HttpIn" protocol="http" port="80" />
</Endpoints>
<Startup>
<Task commandLine="Startup\SetIdleTimeout.cmd" executionContext="elevated" taskType="simple">
<Environment>
<!-- Create the environment variable that informs the startup task whether it is running
in the compute emulator or in the cloud. -->
<Variable name="ComputeEmulatorRunning">
<RoleInstanceValue xpath="/RoleEnvironment/Deployment/@emulated" />
</Variable>
</Environment>
</Task>
</Startup>
<LocalResources>
<LocalStorage name="DiagnosticStore" sizeInMB="20000" cleanOnRoleRecycle="false" />
</LocalResources>
</WebRole>
<WebRole name="Orchard.Azure.Web">
<Sites>
<Site name="Web">
<Bindings>
<Binding name="HttpIn" endpointName="HttpIn" />
</Bindings>
</Site>
</Sites>
<Imports>
<Import moduleName="Diagnostics" />
<Import moduleName="Caching" />
</Imports>
<ConfigurationSettings>
<Setting name="Orchard.Azure.Settings.StorageConnectionString" />
<Setting name="Orchard.Azure.Media.StorageConnectionString" />
<Setting name="Orchard.Azure.OutputCache.HostIdentifier" />
<Setting name="Orchard.Azure.OutputCache.CacheName" />
<Setting name="Orchard.Azure.OutputCache.Hostname" />
<Setting name="Orchard.Azure.OutputCache.Port" />
<Setting name="Orchard.Azure.OutputCache.AuthorizationToken" />
<Setting name="Orchard.Azure.OutputCache.IsSharedCaching" />
<Setting name="Orchard.Azure.DatabaseCache.HostIdentifier" />
<Setting name="Orchard.Azure.DatabaseCache.CacheName" />
<Setting name="Orchard.Azure.DatabaseCache.Hostname" />
<Setting name="Orchard.Azure.DatabaseCache.Port" />
<Setting name="Orchard.Azure.DatabaseCache.AuthorizationToken" />
<Setting name="Orchard.Azure.DatabaseCache.IsSharedCaching" />
</ConfigurationSettings>
<Endpoints>
<InputEndpoint name="HttpIn" protocol="http" port="80" />
</Endpoints>
<Startup>
<Task commandLine="Startup\SetIdleTimeout.cmd" executionContext="elevated" taskType="simple">
<Environment>
<!-- Create the environment variable that informs the startup task whether it is running
in the compute emulator or in the cloud. -->
<Variable name="ComputeEmulatorRunning">
<RoleInstanceValue xpath="/RoleEnvironment/Deployment/@emulated" />
</Variable>
</Environment>
</Task>
</Startup>
<LocalResources>
<LocalStorage name="DiagnosticStore" sizeInMB="20000" cleanOnRoleRecycle="false" />
</LocalResources>
</WebRole>
</ServiceDefinition>

View File

@ -6,22 +6,24 @@ using System.Web;
namespace Orchard.Azure {
public class Constants {
public const string ShellSettingsStorageConnectionStringSettingName = "Orchard.Settings.StorageConnectionString";
public const string ShellSettingsStorageConnectionStringSettingName = "Orchard.Azure.Settings.StorageConnectionString";
public const string ShellSettingsContainerName = "sites"; // Container names must be lower case.
public const string ShellSettingsFileName = "Settings.txt";
public const string MediaStorageFeatureName = "Orchard.Azure";
public const string MediaStorageStorageConnectionStringSettingName = "Orchard.Media.StorageConnectionString";
public const string MediaStorageStorageConnectionStringSettingName = "Orchard.Azure.Media.StorageConnectionString";
public const string MediaStorageContainerName = "media"; // Container names must be lower case.
public const string OutputCacheFeatureName = "Orchard.Azure.OutputCache";
public const string OutputCacheHostIdentifierSettingName = "Azure.OutputCache.HostIdentifier";
public const string OutputCacheCacheNameSettingName = "Azure.OutputCache.CacheName";
public const string OutputCacheIsSharedCachingSettingName = "Azure.OutputCache.IsSharedCaching";
public const string OutputCacheSettingNamePrefix = "Orchard.Azure.OutputCache.";
public const string DatabaseCacheFeatureName = "Orchard.Azure.DatabaseCache";
public const string DatabaseCacheHostIdentifierSettingName = "Azure.DatabaseCache.HostIdentifier";
public const string DatabaseCacheCacheNameSettingName = "Azure.DatabaseCache.CacheName";
public const string DatabaseCacheIsSharedCachingSettingName = "Azure.DatabaseCache.IsSharedCaching";
public const string DatabaseCacheSettingNamePrefix = "Orchard.Azure.DatabaseCache.";
public const string CacheHostIdentifierSettingName = "HostIdentifier";
public const string CacheCacheNameSettingName = "CacheName";
public const string CacheHostnameSettingName = "Hostname";
public const string CachePortSettingName = "Port";
public const string CacheAuthorizationTokenSettingName = "AuthorizationToken";
public const string CacheIsSharedCachingSettingName = "IsSharedCaching";
}
}

View File

@ -143,17 +143,18 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Constants.cs" />
<Compile Include="Services\Caching\CacheClientConfiguration.cs" />
<Compile Include="Services\Caching\Database\AzureCacheClient.cs" />
<Compile Include="Services\Caching\Database\AzureCacheConfiguration.cs" />
<Compile Include="Services\Caching\Database\AzureCacheProvider.cs" />
<Compile Include="Services\Caching\Database\AzureCacheRecord.cs" />
<Compile Include="Services\Caching\Output\AzureOutputCacheStorageProvider.cs" />
<Compile Include="Services\Environment\Configuration\AzureBlobShellSettingsManager.cs" />
<Compile Include="Services\Environment\Configuration\PlatformConfiguration.cs" />
<Compile Include="Services\FileSystems\AzureFileSystem.cs" />
<Compile Include="Services\FileSystems\CloudBlobContainerExtensions.cs" />
<Compile Include="Services\FileSystems\Media\AzureBlobStorageProvider.cs" />
<Compile Include="Services\Logging\AzureDiagnosticsAppender.cs" />
<Compile Include="Services\MissingSettingsBanner.cs" />
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>

View File

@ -0,0 +1,102 @@
using Microsoft.ApplicationServer.Caching;
using Orchard.Azure.Services.Environment.Configuration;
using Orchard.Environment.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;
using System.Web;
namespace Orchard.Azure.Services.Caching {
public class CacheClientConfiguration {
public static CacheClientConfiguration FromPlatformConfiguration(ShellSettings shellSettings, string settingNamePrefix) {
var portString = PlatformConfiguration.GetSetting(Constants.CachePortSettingName, shellSettings, settingNamePrefix);
var isSharedCachingString = PlatformConfiguration.GetSetting(Constants.CacheIsSharedCachingSettingName, shellSettings, settingNamePrefix);
return new CacheClientConfiguration() {
HostIdentifier = PlatformConfiguration.GetSetting(Constants.CacheHostIdentifierSettingName, shellSettings, settingNamePrefix),
CacheName = PlatformConfiguration.GetSetting(Constants.CacheCacheNameSettingName, shellSettings, settingNamePrefix),
Hostname = PlatformConfiguration.GetSetting(Constants.CacheHostnameSettingName, shellSettings, settingNamePrefix),
Port = String.IsNullOrWhiteSpace(portString) ? 0 : Int32.Parse(portString),
AuthorizationToken = PlatformConfiguration.GetSetting(Constants.CacheAuthorizationTokenSettingName, shellSettings, settingNamePrefix),
IsSharedCaching = String.IsNullOrWhiteSpace(isSharedCachingString) ? false : Boolean.Parse(isSharedCachingString)
};
}
public string HostIdentifier {
get;
protected set;
}
public string CacheName {
get;
protected set;
}
public string Hostname {
get;
protected set;
}
public int Port {
get;
protected set;
}
public string AuthorizationToken {
get;
protected set;
}
public bool IsSharedCaching {
get;
protected set;
}
public bool CompressionIsEnabled {
get;
protected set;
}
public bool AutodiscoverIsEnabled {
get {
return String.IsNullOrWhiteSpace(Hostname) || Port == 0 || String.IsNullOrWhiteSpace(AuthorizationToken);
}
}
public void Validate() {
if (AutodiscoverIsEnabled) {
if (String.IsNullOrWhiteSpace(HostIdentifier))
throw new Exception("AutoDiscover mode is detected but HostIdentifier is missing or empty.");
}
}
public DataCache CreateCache() {
var dataCacheFactoryConfiguration = new DataCacheFactoryConfiguration() {
MaxConnectionsToServer = 32,
UseLegacyProtocol = false,
IsCompressionEnabled = CompressionIsEnabled
};
if (AutodiscoverIsEnabled)
dataCacheFactoryConfiguration.AutoDiscoverProperty = new DataCacheAutoDiscoverProperty(true, HostIdentifier);
else {
dataCacheFactoryConfiguration.Servers = new[] { new DataCacheServerEndpoint(Hostname, Port) };
dataCacheFactoryConfiguration.SecurityProperties = new DataCacheSecurity(AuthorizationToken);
}
var dataCacheFactory = new DataCacheFactory(dataCacheFactoryConfiguration);
if (IsSharedCaching || String.IsNullOrEmpty(CacheName))
return dataCacheFactory.GetDefaultCache();
return dataCacheFactory.GetCache(CacheName);
}
public override string ToString() {
string key = String.Format("{0}_{1}_{2}_{3}_{4}_{5}_{6}", HostIdentifier, CacheName, Hostname, Port, AuthorizationToken, IsSharedCaching, CompressionIsEnabled);
return key;
}
}
}

View File

@ -13,36 +13,18 @@ namespace Orchard.Azure.Services.Caching.Database {
[OrchardSuppressDependency("Orchard.Data.DefaultDatabaseCacheConfiguration")]
public class AzureCacheConfiguration : Component, IDatabaseCacheConfiguration {
public static string CacheHostIdentifier;
public static string CacheName;
public static bool IsSharedCaching;
public static CacheClientConfiguration CacheClientConfiguration;
public AzureCacheConfiguration(IShellSettingsManager shellSettingsManager, ShellSettings shellSettings)
public AzureCacheConfiguration(ShellSettings shellSettings)
: base() {
// Create default configuration to local role-based cache when feature is enabled.
var doSave = false;
if (!shellSettings.Keys.Contains(Constants.DatabaseCacheHostIdentifierSettingName)) {
shellSettings[Constants.DatabaseCacheHostIdentifierSettingName] = "Orchard.Azure.Web";
doSave = true;
try {
CacheClientConfiguration = CacheClientConfiguration.FromPlatformConfiguration(shellSettings, Constants.DatabaseCacheSettingNamePrefix);
CacheClientConfiguration.Validate();
}
if (!shellSettings.Keys.Contains(Constants.DatabaseCacheCacheNameSettingName)) {
shellSettings[Constants.DatabaseCacheCacheNameSettingName] = "DatabaseCache";
doSave = true;
catch (Exception ex) {
throw new Exception(String.Format("The {0} configuration settings are missing or invalid.", Constants.DatabaseCacheFeatureName), ex);
}
if (!shellSettings.Keys.Contains(Constants.DatabaseCacheIsSharedCachingSettingName)) {
shellSettings[Constants.DatabaseCacheIsSharedCachingSettingName] = "false";
doSave = true;
}
if (doSave) {
Logger.Information("Added missing shell settings; calling IShellSettingsManager.SaveSettings().");
shellSettingsManager.SaveSettings(shellSettings);
}
CacheHostIdentifier = shellSettings[Constants.DatabaseCacheHostIdentifierSettingName];
CacheName = shellSettings[Constants.DatabaseCacheCacheNameSettingName];
IsSharedCaching = Boolean.Parse(shellSettings[Constants.DatabaseCacheIsSharedCachingSettingName]);
_shellSettings = shellSettings;
}

View File

@ -13,30 +13,16 @@ namespace Orchard.Azure.Services.Caching.Database {
private static IDictionary<string, DataCache> _cacheDictionary = new Dictionary<string, DataCache>();
private static DataCache GetCache(IInternalLogger logger, string cacheHostIdentifier, string cacheName, bool enableCompression) {
string key = String.Format("{0}_{1}_{2}", cacheHostIdentifier, cacheName, enableCompression);
private static DataCache GetCache(IInternalLogger logger, CacheClientConfiguration config) {
string key = config.ToString();
if (!_cacheDictionary.ContainsKey(key)) {
var dataCacheFactoryConfiguration = new DataCacheFactoryConfiguration() {
AutoDiscoverProperty = new DataCacheAutoDiscoverProperty(true, AzureCacheConfiguration.CacheHostIdentifier),
MaxConnectionsToServer = 32,
UseLegacyProtocol = false
};
var dataCacheFactory = new DataCacheFactory(dataCacheFactoryConfiguration);
if (logger.IsDebugEnabled)
logger.DebugFormat("Creating DataCache with CacheHostIdentifier='{0}' and CacheName='{1}'.", cacheHostIdentifier, cacheName);
DataCache newCache;
if (!String.IsNullOrEmpty(cacheName))
newCache = dataCacheFactory.GetCache(cacheName);
else
newCache = dataCacheFactory.GetDefaultCache();
_cacheDictionary[key] = newCache;
logger.DebugFormat("Creating new DataCache with key '{0}'.", key);
_cacheDictionary[key] = AzureCacheConfiguration.CacheClientConfiguration.CreateCache();
}
else {
if (logger.IsDebugEnabled)
logger.DebugFormat("Reusing existing DataCache with CacheHostIdentifier='{0}' and CacheName='{1}'.", cacheHostIdentifier, cacheName);
logger.DebugFormat("Reusing existing DataCache with key '{0}'.", key);
}
return _cacheDictionary[key];
@ -60,15 +46,15 @@ namespace Orchard.Azure.Services.Caching.Database {
// Using static fields to communicate host identifier and cache name from AzureCacheConfiguration to
// this class might cause problems in multi-tenancy scenarios when tenants have different settings
// for these in shell settings. We should think of something more robust.
var cache = GetCache(_logger, AzureCacheConfiguration.CacheHostIdentifier, AzureCacheConfiguration.CacheName, enableCompression);
// for these in platform configuration. We should think of something more robust.
var cache = GetCache(_logger, AzureCacheConfiguration.CacheClientConfiguration);
TimeSpan? expiration = null;
string expirationString;
if (properties.TryGetValue("expiration", out expirationString) || properties.TryGetValue(global::NHibernate.Cfg.Environment.CacheDefaultExpiration, out expirationString))
expiration = TimeSpan.FromSeconds(Int32.Parse(expirationString));
return new AzureCacheClient(cache, AzureCacheConfiguration.IsSharedCaching, regionName, expiration);
return new AzureCacheClient(cache, AzureCacheConfiguration.CacheClientConfiguration.IsSharedCaching, regionName, expiration);
}
public long NextTimestamp() {

View File

@ -14,67 +14,35 @@ namespace Orchard.Azure.Services.Caching.Output {
[OrchardSuppressDependency("Orchard.OutputCache.Services.DefaultCacheStorageProvider")]
public class AzureOutputCacheStorageProvider : Component, IOutputCacheStorageProvider {
public AzureOutputCacheStorageProvider(IShellSettingsManager shellSettingsManager, ShellSettings shellSettings)
public AzureOutputCacheStorageProvider(ShellSettings shellSettings)
: base() {
// Create default configuration to local role-based cache when feature is enabled.
var doSave = false;
if (!shellSettings.Keys.Contains(Constants.OutputCacheHostIdentifierSettingName)) {
shellSettings[Constants.OutputCacheHostIdentifierSettingName] = "Orchard.Azure.Web";
doSave = true;
try {
_cacheConfig = CacheClientConfiguration.FromPlatformConfiguration(shellSettings, Constants.OutputCacheSettingNamePrefix);
_cacheConfig.Validate();
}
if (!shellSettings.Keys.Contains(Constants.OutputCacheCacheNameSettingName)) {
shellSettings[Constants.OutputCacheCacheNameSettingName] = "OutputCache";
doSave = true;
}
if (!shellSettings.Keys.Contains(Constants.OutputCacheIsSharedCachingSettingName)) {
shellSettings[Constants.OutputCacheIsSharedCachingSettingName] = "false";
doSave = true;
catch (Exception ex) {
throw new Exception(String.Format("The {0} configuration settings are missing or invalid.", Constants.OutputCacheFeatureName), ex);
}
if (doSave) {
Logger.Information("Added missing shell settings; calling IShellSettingsManager.SaveSettings().");
shellSettingsManager.SaveSettings(shellSettings);
}
_cache = _cacheConfig.CreateCache();
var cacheHostIdentifier = shellSettings[Constants.OutputCacheHostIdentifierSettingName];
var cacheName = shellSettings[Constants.OutputCacheCacheNameSettingName];
Logger.Debug("Creating cache with HostIdentifier='{0}', CacheName='{1}'.", cacheHostIdentifier, cacheName);
var dataCacheFactoryConfiguration = new DataCacheFactoryConfiguration() {
AutoDiscoverProperty = new DataCacheAutoDiscoverProperty(true, cacheHostIdentifier),
MaxConnectionsToServer = 32,
UseLegacyProtocol = false
};
var dataCacheFactory = new DataCacheFactory(dataCacheFactoryConfiguration);
if (!String.IsNullOrEmpty(cacheName))
_cache = dataCacheFactory.GetCache(cacheName);
else
_cache = dataCacheFactory.GetDefaultCache();
_usingSharedCaching = Boolean.Parse(shellSettings[Constants.OutputCacheIsSharedCachingSettingName]);
if (!_usingSharedCaching) {
if (!_cacheConfig.IsSharedCaching) {
// If not using Windows Azure Shared Caching we can enable additional features by
// storing all cache items in a region. This enables enumerating and counting all
// items currently in the cache.
_region = shellSettings.Name;
_cache.CreateRegion(_region);
}
else
Logger.Debug("Configured to use Shared Caching.");
}
private readonly CacheClientConfiguration _cacheConfig;
private readonly DataCache _cache;
private readonly bool _usingSharedCaching; // True if using Windows Azure Shared Caching rather than role-based caching.
private readonly string _region;
public void Set(string key, CacheItem cacheItem) {
Logger.Debug("Set() invoked with key='{0}' in region '{1}'.", key, _region);
if (_usingSharedCaching)
if (_cacheConfig.IsSharedCaching)
_cache.Put(key, cacheItem);
else
_cache.Put(key, cacheItem, TimeSpan.FromSeconds(cacheItem.ValidFor), _region);
@ -82,7 +50,7 @@ namespace Orchard.Azure.Services.Caching.Output {
public void Remove(string key) {
Logger.Debug("Remove() invoked with key='{0}' in region '{1}'.", key, _region);
if (_usingSharedCaching)
if (_cacheConfig.IsSharedCaching)
_cache.Remove(key);
else
_cache.Remove(key, _region);
@ -90,7 +58,7 @@ namespace Orchard.Azure.Services.Caching.Output {
public void RemoveAll() {
Logger.Debug("RemoveAll() invoked in region '{0}'.", _region);
if (_usingSharedCaching)
if (_cacheConfig.IsSharedCaching)
_cache.Clear();
else
_cache.ClearRegion(_region);
@ -98,7 +66,7 @@ namespace Orchard.Azure.Services.Caching.Output {
public CacheItem GetCacheItem(string key) {
Logger.Debug("GetCacheItem() invoked with key='{0}' in region '{1}'.", key, _region);
if (_usingSharedCaching)
if (_cacheConfig.IsSharedCaching)
return _cache.Get(key) as CacheItem;
else
return _cache.Get(key, _region) as CacheItem;
@ -106,7 +74,7 @@ namespace Orchard.Azure.Services.Caching.Output {
public IEnumerable<CacheItem> GetCacheItems(int skip, int count) {
Logger.Debug("GetCacheItems() invoked in region '{0}'.", _region);
if (_usingSharedCaching) {
if (_cacheConfig.IsSharedCaching) {
Logger.Debug("Enumeration not supported with Shared Caching; returning empty enumerable.");
return Enumerable.Empty<CacheItem>(); // Enumeration not supported with Shared Caching.
}
@ -121,7 +89,7 @@ namespace Orchard.Azure.Services.Caching.Output {
public int GetCacheItemsCount() {
Logger.Debug("GetCacheItemsCount() invoked in region '{0}'.", _region);
if (_usingSharedCaching) {
if (_cacheConfig.IsSharedCaching) {
Logger.Debug("Enumeration not supported with Shared Caching; returning zero.");
return 0; // Enumeration not supported with Shared Caching.
}

View File

@ -0,0 +1,26 @@
using Microsoft.WindowsAzure;
using Orchard.Environment.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Orchard.Azure.Services.Environment.Configuration {
public static class PlatformConfiguration {
/// <summary>
/// Reads a setting from platform configuration, trying first prefixed with the current tenant name and
/// secondly with no prefix.
/// </summary>
/// <param name="name">The name of the setting to read.</param>
/// <param name="shellSettings">The ShellSettings object for the current tenant.</param>
/// <param name="namePrefix">An optional prefix to prepend the setting name with.</param>
/// <returns>The value of the setting if found with or without tenant name prefix, otherwise null.</returns>
public static string GetSetting(string name, ShellSettings shellSettings, string namePrefix = null) {
var tenantName = String.Format("{0}_{1}{2}", shellSettings.Name, namePrefix, name);
var fallbackName = String.Format("{0}{1}", namePrefix, name);
return CloudConfigurationManager.GetSetting(tenantName) ?? CloudConfigurationManager.GetSetting(fallbackName);
}
}
}

View File

@ -1,8 +1,8 @@
using System.IO;
using Orchard.Azure.Services.Environment.Configuration;
using Orchard.Environment.Configuration;
using Orchard.FileSystems.Media;
using Orchard.Environment.Extensions;
using Microsoft.WindowsAzure;
using Orchard.FileSystems.Media;
namespace Orchard.Azure.Services.FileSystems.Media {
@ -10,8 +10,13 @@ namespace Orchard.Azure.Services.FileSystems.Media {
[OrchardSuppressDependency("Orchard.FileSystems.Media.FileSystemStorageProvider")]
public class AzureBlobStorageProvider : AzureFileSystem, IStorageProvider {
public AzureBlobStorageProvider(ShellSettings shellSettings, IMimeTypeProvider mimeTypeProvider) : base(CloudConfigurationManager.GetSetting(Constants.MediaStorageStorageConnectionStringSettingName), Constants.MediaStorageContainerName, shellSettings.Name, false, mimeTypeProvider)
{ }
public AzureBlobStorageProvider(ShellSettings shellSettings, IMimeTypeProvider mimeTypeProvider)
: this(PlatformConfiguration.GetSetting(Constants.MediaStorageStorageConnectionStringSettingName, shellSettings), Constants.MediaStorageContainerName, shellSettings.Name, mimeTypeProvider) {
}
public AzureBlobStorageProvider(string storageConnectionString, string containerName, string rootFolderPath, IMimeTypeProvider mimeTypeProvider)
: base(storageConnectionString, containerName, rootFolderPath, false, mimeTypeProvider) {
}
public bool TrySaveStream(string path, Stream inputStream) {
try {

View File

@ -1,85 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Orchard.Localization;
using Orchard.UI.Admin.Notification;
using Orchard.UI.Notify;
using Orchard.Environment.Features;
using Orchard.Environment.Configuration;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Storage;
namespace Orchard.Azure.Services {
public class MissingSettingsBanner : INotificationProvider {
public MissingSettingsBanner(IFeatureManager featureManager, ShellSettings shellSettings) {
_featureManager = featureManager;
_shellSettings = shellSettings;
T = NullLocalizer.Instance;
}
private IFeatureManager _featureManager;
private ShellSettings _shellSettings;
public Localizer T {
get;
set;
}
public IEnumerable<NotifyEntry> GetNotifications() {
var enabledFeatureNamesQuery =
from feature in _featureManager.GetEnabledFeatures()
select feature.Id;
if (enabledFeatureNamesQuery.Contains(Constants.MediaStorageFeatureName)) {
CloudStorageAccount storageAccount = null;
var storageConnectionString = CloudConfigurationManager.GetSetting(Constants.MediaStorageStorageConnectionStringSettingName);
var isValid = CloudStorageAccount.TryParse(storageConnectionString, out storageAccount);
if (!isValid)
yield return new NotifyEntry {
Message = T("A valid storage account connection string must be configured in the role configuration setting '{0}'.", Constants.MediaStorageStorageConnectionStringSettingName),
Type = NotifyType.Warning
};
}
if (enabledFeatureNamesQuery.Contains(Constants.OutputCacheFeatureName)) {
if (String.IsNullOrWhiteSpace(_shellSettings[Constants.OutputCacheHostIdentifierSettingName]))
yield return new NotifyEntry {
Message = T("A cache cluster host identifier must be configured in the shell setting '{0}'.", Constants.OutputCacheHostIdentifierSettingName),
Type = NotifyType.Warning
};
if (String.IsNullOrWhiteSpace(_shellSettings[Constants.OutputCacheCacheNameSettingName]))
yield return new NotifyEntry {
Message = T("A cache name must be configured in the shell setting '{0}'.", Constants.OutputCacheCacheNameSettingName),
Type = NotifyType.Warning
};
bool result;
if (!Boolean.TryParse(_shellSettings[Constants.OutputCacheIsSharedCachingSettingName], out result))
yield return new NotifyEntry {
Message = T("A valid boolean value must be configured in the shell setting '{0}'.", Constants.OutputCacheIsSharedCachingSettingName),
Type = NotifyType.Warning
};
}
if (enabledFeatureNamesQuery.Contains(Constants.DatabaseCacheFeatureName)) {
if (String.IsNullOrWhiteSpace(_shellSettings[Constants.DatabaseCacheHostIdentifierSettingName]))
yield return new NotifyEntry {
Message = T("A cache cluster host identifier must be configured in the shell setting '{0}'.", Constants.DatabaseCacheHostIdentifierSettingName),
Type = NotifyType.Warning
};
if (String.IsNullOrWhiteSpace(_shellSettings[Constants.DatabaseCacheCacheNameSettingName]))
yield return new NotifyEntry {
Message = T("A cache name must be configured in the shell setting '{0}'.", Constants.DatabaseCacheCacheNameSettingName),
Type = NotifyType.Warning
};
bool result;
if (!Boolean.TryParse(_shellSettings[Constants.DatabaseCacheIsSharedCachingSettingName], out result))
yield return new NotifyEntry {
Message = T("A valid boolean value must be configured in the shell setting '{0}'.", Constants.DatabaseCacheIsSharedCachingSettingName),
Type = NotifyType.Warning
};
}
}
}
}