From d0c7091964b7a76734fdfd4320a0a5c80d485731 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Tue, 30 Sep 2014 16:25:49 -0700 Subject: [PATCH] Adding Orchard.Redis module --- .../Modules/Orchard.Azure/Module.txt | 5 - .../Orchard.Azure/Orchard.Azure.csproj | 4 - .../AzureRedisOutputCacheStorageProvider.cs | 166 ------------------ .../Brokers/SqlServer/Worker.cs | 16 +- .../Services/DefaultMessageBus.cs | 12 ++ .../Modules/Orchard.OutputCache/Module.txt | 2 +- .../Configuration/IRedisConnectionProvider.cs | 10 ++ .../Configuration/RedisConnectionProvider.cs | 47 +++++ .../MessageBus/RedisMessageBusBroker.cs | 80 +++++++++ .../Modules/Orchard.Redis/Module.txt | 22 +++ .../Orchard.Redis/Orchard.Redis.csproj | 153 ++++++++++++++++ .../RedisOutputCacheStorageProvider.cs | 113 ++++++++++++ .../Orchard.Redis/Properties/AssemblyInfo.cs | 37 ++++ .../Modules/Orchard.Redis/Web.config | 41 +++++ src/Orchard.sln | 13 ++ 15 files changed, 537 insertions(+), 184 deletions(-) delete mode 100644 src/Orchard.Web/Modules/Orchard.Azure/Services/Caching/Output/AzureRedisOutputCacheStorageProvider.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Redis/Configuration/IRedisConnectionProvider.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Redis/Configuration/RedisConnectionProvider.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Redis/MessageBus/RedisMessageBusBroker.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Redis/Module.txt create mode 100644 src/Orchard.Web/Modules/Orchard.Redis/Orchard.Redis.csproj create mode 100644 src/Orchard.Web/Modules/Orchard.Redis/OutputCache/RedisOutputCacheStorageProvider.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Redis/Properties/AssemblyInfo.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Redis/Web.config diff --git a/src/Orchard.Web/Modules/Orchard.Azure/Module.txt b/src/Orchard.Web/Modules/Orchard.Azure/Module.txt index a3c4bd1e0..db10c6055 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Azure/Module.txt @@ -17,11 +17,6 @@ Features: Description: Activates an Orchard output cache provider that targets Windows Azure Cache. Dependencies: Orchard.Azure, Orchard.OutputCache Category: Performance - Orchard.Azure.RedisOutputCache: - Name: Microsoft Azure Redis Output Cache - Description: Activates an Orchard output cache provider that targets Windows Azure Redis Cache. - Dependencies: Orchard.Azure, Orchard.OutputCache - Category: Performance Orchard.Azure.DatabaseCache: Name: Microsoft Azure Database Cache Description: Activates an NHibernate second-level cache provider that targets Microsoft Azure Cache. diff --git a/src/Orchard.Web/Modules/Orchard.Azure/Orchard.Azure.csproj b/src/Orchard.Web/Modules/Orchard.Azure/Orchard.Azure.csproj index aa6a2c637..a9fe59a56 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure/Orchard.Azure.csproj +++ b/src/Orchard.Web/Modules/Orchard.Azure/Orchard.Azure.csproj @@ -93,9 +93,6 @@ False ..\..\..\..\lib\nhibernate\NHibernate.dll - - ..\..\..\..\lib\redis\StackExchange.Redis.dll - @@ -111,7 +108,6 @@ - diff --git a/src/Orchard.Web/Modules/Orchard.Azure/Services/Caching/Output/AzureRedisOutputCacheStorageProvider.cs b/src/Orchard.Web/Modules/Orchard.Azure/Services/Caching/Output/AzureRedisOutputCacheStorageProvider.cs deleted file mode 100644 index 3b1647d94..000000000 --- a/src/Orchard.Web/Modules/Orchard.Azure/Services/Caching/Output/AzureRedisOutputCacheStorageProvider.cs +++ /dev/null @@ -1,166 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using Microsoft.ApplicationServer.Caching; -using Newtonsoft.Json; -using Orchard.Azure.Services.Environment.Configuration; -using Orchard.Caching; -using Orchard.Environment.Configuration; -using Orchard.Environment.Extensions; -using Orchard.Logging; -using Orchard.OutputCache.Models; -using Orchard.OutputCache.Services; -using StackExchange.Redis; - -namespace Orchard.Azure.Services.Caching.Output { - - [OrchardFeature("Orchard.Azure.RedisOutputCache")] - [OrchardSuppressDependency("Orchard.OutputCache.Services.DefaultCacheStorageProvider")] - public class AzureRedisCacheStorageProvider : Component, IOutputCacheStorageProvider { - public const string DataCacheKey = "DataCache"; - public const string ClientConfigurationKey = "CacheClientConfiguration"; - - private CacheClientConfiguration _cacheClientConfiguration; - private static ConcurrentDictionary _connectionMultiplexers = new ConcurrentDictionary(); - - private readonly ICacheManager _cacheManager; - private readonly ShellSettings _shellSettings; - private readonly IPlatformConfigurationAccessor _pca; - private HashSet _keysCache; - - public AzureRedisCacheStorageProvider( - ShellSettings shellSettings, - IPlatformConfigurationAccessor pca, - ICacheManager cacheManager) { - _cacheManager = cacheManager; - _shellSettings = shellSettings; - _pca = pca; - - Logger = NullLogger.Instance; - } - - public CacheClientConfiguration CacheConfiguration { - get { - // the configuration is backed by a field so that we don't call the cacheManager multiple times in the same request - // cache configurations are stored in the cacheManager so that we don't read the config on each request - if (_cacheClientConfiguration == null) { - - _cacheClientConfiguration = _cacheManager.Get(ClientConfigurationKey, ctx => { - CacheClientConfiguration cacheConfig; - try { - cacheConfig = CacheClientConfiguration.FromPlatformConfiguration( - _shellSettings.Name, - Constants.OutputCacheSettingNamePrefix, - _pca); - - cacheConfig.Validate(); - return cacheConfig; - } - catch (Exception ex) { - throw new Exception(String.Format("The {0} configuration settings are missing or invalid.", Constants.OutputCacheFeatureName), ex); - } - }); - - if (_cacheClientConfiguration == null) { - throw new InvalidOperationException("Could not create a valid cache configuration"); - } - } - - return _cacheClientConfiguration; - } - } - - public IDatabase Cache { - get { - - return GetConnection().GetDatabase(); - } - } - - private ConnectionMultiplexer GetConnection() { - var connectionMultiplexer = _connectionMultiplexers.GetOrAdd(CacheConfiguration, cfg => { - Logger.Debug("Creating a new cache client ({0})", CacheConfiguration.GetHashCode()); - var connectionString = cfg.HostIdentifier + ",password=" + cfg.AuthorizationToken; - return ConnectionMultiplexer.Connect(connectionString); - }); - - - return connectionMultiplexer; - } - - public void Set(string key, CacheItem cacheItem) { - if (cacheItem.ValidFor <= 0) { - return; - } - - var value = JsonConvert.SerializeObject(cacheItem); - Cache.StringSet(GetLocalizedKey(key), value, TimeSpan.FromSeconds(cacheItem.ValidFor)); - } - - public void Remove(string key) { - Cache.KeyDelete(GetLocalizedKey(key)); - } - - public void RemoveAll() { - foreach (var key in GetAllKeys()) { - Remove(key); - } - } - - public CacheItem GetCacheItem(string key) { - string value = Cache.StringGet(GetLocalizedKey(key)); - if(String.IsNullOrEmpty(value)) { - return null; - } - - return JsonConvert.DeserializeObject(value); - } - - public IEnumerable GetCacheItems(int skip, int count) { - foreach (var key in GetAllKeys().Skip(skip).Take(count)) { - var cacheItem = GetCacheItem(key); - // the item could have expired in the meantime - if (cacheItem != null) { - yield return cacheItem; - } - } - } - - public int GetCacheItemsCount() { - return GetAllKeys().Count(); - } - - /// - /// Creates a namespaced key to support multiple tenants on top of a single Redis connection. - /// - /// The key to localized. - /// A localized key based on the tenant name. - private string GetLocalizedKey(string key) { - return _shellSettings.Name + ":" + key; - } - - /// - /// Returns all the keys for the current tenant. - /// - /// The keys for the current tenant. - private IEnumerable GetAllKeys() { - // prevent the same request from computing the list twice (count + list) - if (_keysCache == null) { - _keysCache = new HashSet(); - var prefix = GetLocalizedKey(""); - - var connection = GetConnection(); - foreach (var endPoint in connection.GetEndPoints()) { - var server = GetConnection().GetServer(endPoint); - foreach (var key in server.Keys(pattern: GetLocalizedKey("*"))) { - _keysCache.Add(key.ToString().Substring(prefix.Length)); - } - } - } - - return _keysCache; - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MessageBus/Brokers/SqlServer/Worker.cs b/src/Orchard.Web/Modules/Orchard.MessageBus/Brokers/SqlServer/Worker.cs index 4bac8d4ba..cc6ab616e 100644 --- a/src/Orchard.Web/Modules/Orchard.MessageBus/Brokers/SqlServer/Worker.cs +++ b/src/Orchard.Web/Modules/Orchard.MessageBus/Brokers/SqlServer/Worker.cs @@ -145,16 +145,16 @@ namespace Orchard.MessageBus.Brokers.SqlServer { GetHandlersForChannel(channel).Add(handler); } - private List> GetHandlersForChannel(string channel) { - List> channelHandlers; + private List> GetHandlersForChannel(string channel) { + List> channelHandlers; - if(!_handlers.TryGetValue(channel, out channelHandlers)) { - channelHandlers = new List>(); - _handlers.Add(channel, channelHandlers); - } + if(!_handlers.TryGetValue(channel, out channelHandlers)) { + channelHandlers = new List>(); + _handlers.Add(channel, channelHandlers); + } - return channelHandlers; - } + return channelHandlers; + } public SqlCommand CreateCommand(SqlConnection connection) { SqlCommand command = new SqlCommand(commandText, connection); diff --git a/src/Orchard.Web/Modules/Orchard.MessageBus/Services/DefaultMessageBus.cs b/src/Orchard.Web/Modules/Orchard.MessageBus/Services/DefaultMessageBus.cs index 876b87d0a..e38098db8 100644 --- a/src/Orchard.Web/Modules/Orchard.MessageBus/Services/DefaultMessageBus.cs +++ b/src/Orchard.Web/Modules/Orchard.MessageBus/Services/DefaultMessageBus.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Web; using System.Threading.Tasks; +using Orchard.Logging; namespace Orchard.MessageBus.Services { public class DefaultMessageBus : IMessageBus { @@ -10,14 +11,19 @@ namespace Orchard.MessageBus.Services { public DefaultMessageBus(IEnumerable messageBrokers) { _messageBroker = messageBrokers.FirstOrDefault(); + + Logger = NullLogger.Instance; } + public ILogger Logger { get; set; } + public void Subscribe(string channel, Action handler) { if (_messageBroker == null) { return; } _messageBroker.Subscribe(channel, handler); + Logger.Debug("{0} subscribed to {1}", GetHostName(), channel); } public void Publish(string channel, string message) { @@ -26,6 +32,12 @@ namespace Orchard.MessageBus.Services { } _messageBroker.Publish(channel, message); + Logger.Debug("{0} published {1}", GetHostName(), channel); + } + + private string GetHostName() { + // use the current host and the process id as two servers could run on the same machine + return System.Net.Dns.GetHostName() + ":" + System.Diagnostics.Process.GetCurrentProcess().Id; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Module.txt b/src/Orchard.Web/Modules/Orchard.OutputCache/Module.txt index e20077aff..30e696b98 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Module.txt @@ -12,4 +12,4 @@ Features: Orchard.OutputCache.Database: Description: Stores output cache data in the database. Category: Performance - Dependencies: Orchard.OutputCache + Dependencies: Orchard.OutputCache diff --git a/src/Orchard.Web/Modules/Orchard.Redis/Configuration/IRedisConnectionProvider.cs b/src/Orchard.Web/Modules/Orchard.Redis/Configuration/IRedisConnectionProvider.cs new file mode 100644 index 000000000..5caeba2a1 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Redis/Configuration/IRedisConnectionProvider.cs @@ -0,0 +1,10 @@ +using StackExchange.Redis; + +namespace Orchard.Redis.Configuration { + public interface IRedisConnectionProvider : ISingletonDependency { + + ConnectionMultiplexer GetConnection(string connectionString); + + string GetConnectionString(string service); + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Redis/Configuration/RedisConnectionProvider.cs b/src/Orchard.Web/Modules/Orchard.Redis/Configuration/RedisConnectionProvider.cs new file mode 100644 index 000000000..e73bc365f --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Redis/Configuration/RedisConnectionProvider.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Concurrent; +using System.Configuration; +using Orchard.Environment.Configuration; +using Orchard.Logging; +using StackExchange.Redis; + +namespace Orchard.Redis.Configuration { + public class RedisConnectionProvider : IRedisConnectionProvider { + private static ConcurrentDictionary _connectionMultiplexers = new ConcurrentDictionary(); + private readonly ShellSettings _shellSettings; + + public RedisConnectionProvider(ShellSettings shellSettings) { + _shellSettings = shellSettings; + Logger = NullLogger.Instance; + } + + public ILogger Logger { get; set; } + + public string GetConnectionString(string service) { + var _tenantSettingsKey = _shellSettings.Name + ":" + service; + var _defaultSettingsKey = service; + + var connectionStringSettings = ConfigurationManager.ConnectionStrings[_tenantSettingsKey] ?? ConfigurationManager.ConnectionStrings[_defaultSettingsKey]; + + if (connectionStringSettings == null) { + throw new ConfigurationErrorsException("A connection string is expected for " + service); + } + + return connectionStringSettings.ConnectionString; + } + + public ConnectionMultiplexer GetConnection(string connectionString) { + + if (String.IsNullOrWhiteSpace(connectionString)) { + throw new ArgumentNullException("connectionString"); + } + + var connectionMultiplexer = _connectionMultiplexers.GetOrAdd(connectionString, cfg => { + Logger.Debug("Creating a new cache client for: {0}", connectionString); + return ConnectionMultiplexer.Connect(connectionString); + }); + + return connectionMultiplexer; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Redis/MessageBus/RedisMessageBusBroker.cs b/src/Orchard.Web/Modules/Orchard.Redis/MessageBus/RedisMessageBusBroker.cs new file mode 100644 index 000000000..90b1d7d09 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Redis/MessageBus/RedisMessageBusBroker.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Concurrent; +using System.Linq; +using Orchard.Environment.Configuration; +using Orchard.Environment.Extensions; +using Orchard.Logging; +using Orchard.MessageBus.Services; +using Orchard.Redis.Configuration; +using StackExchange.Redis; + +namespace Orchard.Redis.MessageBus { + + [OrchardFeature("Orchard.Redis.MessageBus")] + public class RedisMessageBusBroker : Component, IMessageBroker { + + private readonly IRedisConnectionProvider _redisConnectionProvider; + + public const string ConnectionStringKey = "Orchard.Redis.MessageBus"; + private readonly string _connectionString; + + private ConcurrentDictionary>> _handlers = new ConcurrentDictionary>>(); + + public RedisMessageBusBroker(ShellSettings shellSettings, IRedisConnectionProvider redisConnectionProvider) { + _redisConnectionProvider = redisConnectionProvider; + _connectionString = _redisConnectionProvider.GetConnectionString(ConnectionStringKey); + } + + public IDatabase Database { + get { + return _redisConnectionProvider.GetConnection(_connectionString).GetDatabase(); + } + } + + public void Subscribe(string channel, Action handler) { + + try { + var channelHandlers = _handlers.GetOrAdd(channel, c => { + return new ConcurrentBag>(); + }); + + channelHandlers.Add(handler); + + var sub = _redisConnectionProvider.GetConnection(_connectionString).GetSubscriber(); + sub.Subscribe(channel, (c, m) => { + + // the message contains the publisher before the first '/' + var messageTokens = m.ToString().Split('/'); + var publisher = messageTokens.FirstOrDefault(); + var message = messageTokens.Skip(1).FirstOrDefault(); + + if (String.IsNullOrWhiteSpace(publisher)) { + return; + } + + // ignore self sent messages + if (GetHostName().Equals(publisher, StringComparison.OrdinalIgnoreCase)) { + return; + } + + Logger.Debug("Processing {0}", message); + handler(c, message); + }); + + } + catch (Exception e) { + Logger.Error("An error occured while subscribing to " + channel, e); + } + } + + public void Publish(string channel, string message) { + Database.Publish(channel, GetHostName() + "/" + message); + } + + private string GetHostName() { + // use the current host and the process id as two servers could run on the same machine + return System.Net.Dns.GetHostName() + ":" + System.Diagnostics.Process.GetCurrentProcess().Id; + } + + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Redis/Module.txt b/src/Orchard.Web/Modules/Orchard.Redis/Module.txt new file mode 100644 index 000000000..7678a5459 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Redis/Module.txt @@ -0,0 +1,22 @@ +Name: Orchard.Redis +AntiForgery: enabled +Author: The Orchard Team +Website: http://orchardproject.net +Version: 1.0 +OrchardVersion: 1.0 +Description: Provides Redis integration with Orchard. +Features: + Orchard.Redis + Name: Redis + Description: Used to provide Redis related functionalities. + Category: Hosting + Orchard.Redis.MessageBus: + Name: Redis Message Bus + Description: A message bus implementation using Redis pub/sub. + Category: Hosting + Dependencies: Orchard.MessageBus, Orchard.Redis + Orchard.Redis.OutputCache: + Name: Redis Output Cache + Description: An output cache storage provider using Redis. + Category: Performance + Dependencies: Orchard.OutputCache, Orchard.Redis diff --git a/src/Orchard.Web/Modules/Orchard.Redis/Orchard.Redis.csproj b/src/Orchard.Web/Modules/Orchard.Redis/Orchard.Redis.csproj new file mode 100644 index 000000000..78355629e --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Redis/Orchard.Redis.csproj @@ -0,0 +1,153 @@ + + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {2C5EB8B3-A313-413D-BAA0-5C21D2A6EC6E} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + Orchard.MessageBus + Orchard.MessageBus + v4.5.1 + false + + + 4.0 + + + false + + + + + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + AllRules.ruleset + false + + + pdbonly + true + bin\ + TRACE + prompt + 4 + AllRules.ruleset + false + + + + + ..\..\..\..\lib\newtonsoft.json\Newtonsoft.Json.dll + + + False + ..\..\..\..\lib\nhibernate\NHibernate.dll + + + ..\..\..\..\lib\redis\StackExchange.Redis.dll + True + + + + + 3.5 + + + + False + ..\..\..\..\lib\aspnetmvc\System.Web.Mvc.dll + + + + + + + + + + + + + + + + + {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} + Orchard.Framework + + + {9916839C-39FC-4CEB-A5AF-89CA7E87119F} + Orchard.Core + + + {ed715544-e649-4f48-b8ee-9368c41c3ac0} + Orchard.MessageBus + + + {6e444ff1-a47c-4cf6-bb3f-507c8ebd776d} + Orchard.OutputCache + + + + + + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + $(ProjectDir)\..\Manifests + + + + + + + + + + + + False + True + 45979 + / + + + False + True + http://orchard.codeplex.com + False + + + + + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Redis/OutputCache/RedisOutputCacheStorageProvider.cs b/src/Orchard.Web/Modules/Orchard.Redis/OutputCache/RedisOutputCacheStorageProvider.cs new file mode 100644 index 000000000..64a0d393d --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Redis/OutputCache/RedisOutputCacheStorageProvider.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using Orchard.Environment.Configuration; +using Orchard.Environment.Extensions; +using Orchard.Logging; +using Orchard.Redis.Configuration; +using Orchard.OutputCache.Models; +using Orchard.OutputCache.Services; +using StackExchange.Redis; + +namespace Orchard.Redis.OutputCache { + + [OrchardFeature("Orchard.Redis.OutputCache")] + [OrchardSuppressDependency("Orchard.OutputCache.Services.DefaultCacheStorageProvider")] + public class RedisOutputCacheStorageProvider : Component, IOutputCacheStorageProvider { + + private readonly ShellSettings _shellSettings; + private readonly IRedisConnectionProvider _redisConnectionProvider; + private HashSet _keysCache; + + public const string ConnectionStringKey = "Orchard.Redis.OutputCache"; + private readonly string _connectionString; + + public RedisOutputCacheStorageProvider(ShellSettings shellSettings, IRedisConnectionProvider redisConnectionProvider) { + _shellSettings = shellSettings; + _redisConnectionProvider = redisConnectionProvider; + _connectionString = _redisConnectionProvider.GetConnectionString(ConnectionStringKey); + + Logger = NullLogger.Instance; + } + + public IDatabase Database { + get { + return _redisConnectionProvider.GetConnection(_connectionString).GetDatabase(); + } + } + + public void Set(string key, CacheItem cacheItem) { + if (cacheItem.ValidFor <= 0) { + return; + } + + var value = JsonConvert.SerializeObject(cacheItem); + Database.StringSet(GetLocalizedKey(key), value, TimeSpan.FromSeconds(cacheItem.ValidFor)); + } + + public void Remove(string key) { + Database.KeyDelete(GetLocalizedKey(key)); + } + + public void RemoveAll() { + foreach (var key in GetAllKeys()) { + Remove(key); + } + } + + public CacheItem GetCacheItem(string key) { + string value = Database.StringGet(GetLocalizedKey(key)); + if(String.IsNullOrEmpty(value)) { + return null; + } + + return JsonConvert.DeserializeObject(value); + } + + public IEnumerable GetCacheItems(int skip, int count) { + foreach (var key in GetAllKeys().Skip(skip).Take(count)) { + var cacheItem = GetCacheItem(key); + // the item could have expired in the meantime + if (cacheItem != null) { + yield return cacheItem; + } + } + } + + public int GetCacheItemsCount() { + return GetAllKeys().Count(); + } + + /// + /// Creates a namespaced key to support multiple tenants on top of a single Redis connection. + /// + /// The key to localized. + /// A localized key based on the tenant name. + private string GetLocalizedKey(string key) { + return _shellSettings.Name + ":" + key; + } + + /// + /// Returns all the keys for the current tenant. + /// + /// The keys for the current tenant. + private IEnumerable GetAllKeys() { + // prevent the same request from computing the list twice (count + list) + if (_keysCache == null) { + _keysCache = new HashSet(); + var prefix = GetLocalizedKey(""); + + var connection = _redisConnectionProvider.GetConnection(_connectionString); + foreach (var endPoint in connection.GetEndPoints()) { + var server = connection.GetServer(endPoint); + foreach (var key in server.Keys(pattern: GetLocalizedKey("*"))) { + _keysCache.Add(key.ToString().Substring(prefix.Length)); + } + } + } + + return _keysCache; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Redis/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Redis/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..fc426464d --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Redis/Properties/AssemblyInfo.cs @@ -0,0 +1,37 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Orchard.Redis")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyProduct("Orchard")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("f4511dd5-71d3-438d-b5a2-42f0461833be")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + diff --git a/src/Orchard.Web/Modules/Orchard.Redis/Web.config b/src/Orchard.Web/Modules/Orchard.Redis/Web.config new file mode 100644 index 000000000..6fc84bc30 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Redis/Web.config @@ -0,0 +1,41 @@ + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.sln b/src/Orchard.sln index 216369f8b..3a4ee4d07 100644 --- a/src/Orchard.sln +++ b/src/Orchard.sln @@ -245,6 +245,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.AuditTrail", "Orcha EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.MessageBus", "Orchard.Web\Modules\Orchard.MessageBus\Orchard.MessageBus.csproj", "{ED715544-E649-4F48-B8EE-9368C41C3AC0}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Redis", "Orchard.Web\Modules\Orchard.Redis\Orchard.Redis.csproj", "{2C5EB8B3-A313-413D-BAA0-5C21D2A6EC6E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution CodeCoverage|Any CPU = CodeCoverage|Any CPU @@ -1017,6 +1019,16 @@ Global {ED715544-E649-4F48-B8EE-9368C41C3AC0}.FxCop|Any CPU.ActiveCfg = Release|Any CPU {ED715544-E649-4F48-B8EE-9368C41C3AC0}.Release|Any CPU.ActiveCfg = Release|Any CPU {ED715544-E649-4F48-B8EE-9368C41C3AC0}.Release|Any CPU.Build.0 = Release|Any CPU + {2C5EB8B3-A313-413D-BAA0-5C21D2A6EC6E}.CodeCoverage|Any CPU.ActiveCfg = Release|Any CPU + {2C5EB8B3-A313-413D-BAA0-5C21D2A6EC6E}.CodeCoverage|Any CPU.Build.0 = Release|Any CPU + {2C5EB8B3-A313-413D-BAA0-5C21D2A6EC6E}.Coverage|Any CPU.ActiveCfg = Release|Any CPU + {2C5EB8B3-A313-413D-BAA0-5C21D2A6EC6E}.Coverage|Any CPU.Build.0 = Release|Any CPU + {2C5EB8B3-A313-413D-BAA0-5C21D2A6EC6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2C5EB8B3-A313-413D-BAA0-5C21D2A6EC6E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2C5EB8B3-A313-413D-BAA0-5C21D2A6EC6E}.FxCop|Any CPU.ActiveCfg = Release|Any CPU + {2C5EB8B3-A313-413D-BAA0-5C21D2A6EC6E}.FxCop|Any CPU.Build.0 = Release|Any CPU + {2C5EB8B3-A313-413D-BAA0-5C21D2A6EC6E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2C5EB8B3-A313-413D-BAA0-5C21D2A6EC6E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1097,5 +1109,6 @@ Global {14A96B1A-9DC9-44C8-A675-206329E15263} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5} {3DD574CD-9C5D-4A45-85E1-EBBA64C22B5F} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5} {ED715544-E649-4F48-B8EE-9368C41C3AC0} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5} + {2C5EB8B3-A313-413D-BAA0-5C21D2A6EC6E} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5} EndGlobalSection EndGlobal