Building out caching

Passing along signal of VPP file monitoring
Expiring results as appropriate in AvailableExtensions

--HG--
branch : dev
This commit is contained in:
Louis DeJardin
2010-05-16 12:59:04 -07:00
parent c138cc996d
commit d46d94f1ee
30 changed files with 410 additions and 146 deletions

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Orchard.Caching;
using Orchard.Environment;
using Autofac;
using Orchard.Environment.FileSystems;
using Orchard.Services;
namespace Orchard.Tests.Caching {
[TestFixture]
public class CacheScopeTests {
private IContainer _hostContainer;
[SetUp]
public void Init() {
_hostContainer = OrchardStarter.CreateHostContainer(builder => {
builder.RegisterType<Alpha>().InstancePerDependency();
});
}
public class Alpha {
public ICacheManager CacheManager { get; set; }
public Alpha(ICacheManager cacheManager) {
CacheManager = cacheManager;
}
}
[Test]
public void ComponentsAtHostLevelHaveAccessToCache() {
var alpha = _hostContainer.Resolve<Alpha>();
Assert.That(alpha.CacheManager, Is.Not.Null);
}
[Test]
public void HostLevelHasAccessToGlobalVolatileProviders() {
Assert.That(_hostContainer.Resolve<IVirtualPathProvider>(), Is.Not.Null);
Assert.That(_hostContainer.Resolve<IAppDataFolder>(), Is.Not.Null);
Assert.That(_hostContainer.Resolve<IClock>(), Is.Not.Null);
}
}
}

View File

@@ -1,4 +1,5 @@
using Autofac;
using System;
using Autofac;
using NUnit.Framework;
using Orchard.Caching;
@@ -11,9 +12,12 @@ namespace Orchard.Tests.Caching {
[SetUp]
public void Init() {
var builder = new ContainerBuilder();
builder.RegisterModule(new CacheModule());
builder.RegisterType<DefaultCacheManager>().As<ICacheManager>();
builder.RegisterType<DefaultCacheHolder>().As<ICacheHolder>().SingleInstance();
builder.RegisterType<DefaultCacheManager>().As<ICacheManager>();
_container = builder.Build();
_cacheManager = _container.Resolve<ICacheManager>();
_cacheManager = _container.Resolve<ICacheManager>(new TypedParameter(typeof(Type), GetType()));
}
[Test]
@@ -28,5 +32,66 @@ namespace Orchard.Tests.Caching {
var result = _cacheManager.Get("testItem", ctx => "");
Assert.That(result, Is.EqualTo("testResult"));
}
[Test]
public void CacheModuleProvidesTypeSpecificManager() {
var scope = _container.BeginLifetimeScope(builder => {
builder.RegisterModule(new CacheModule());
builder.RegisterType<ComponentOne>();
builder.RegisterType<ComponentTwo>();
});
var c1 = scope.Resolve<ComponentOne>();
var c2 = scope.Resolve<ComponentTwo>();
var w1a = c1.CacheManager.Get("hello", ctx => "world1");
var w1b = c1.CacheManager.Get("hello", ctx => "world2");
var w2a = c2.CacheManager.Get("hello", ctx => "world3");
var w2b = c2.CacheManager.Get("hello", ctx => "world4");
Assert.That(w1a, Is.EqualTo("world1"));
Assert.That(w1b, Is.EqualTo("world1"));
Assert.That(w2a, Is.EqualTo("world3"));
Assert.That(w2b, Is.EqualTo("world3"));
var c3 = scope.Resolve<ComponentOne>();
var c4 = scope.Resolve<ComponentTwo>();
var w3a = c3.CacheManager.Get("hello", ctx => "world5");
var w3b = c3.CacheManager.Get("hello", ctx => "world6");
var w4a = c4.CacheManager.Get("hello", ctx => "world7");
var w4b = c4.CacheManager.Get("hello", ctx => "world8");
Assert.That(w3a, Is.EqualTo("world1"));
Assert.That(w3b, Is.EqualTo("world1"));
Assert.That(w4a, Is.EqualTo("world3"));
Assert.That(w4b, Is.EqualTo("world3"));
Assert.That(c1.CacheManager,
Is.Not.SameAs(c3.CacheManager));
Assert.That(c1.CacheManager.GetCache<string, string>(),
Is.SameAs(c3.CacheManager.GetCache<string, string>()));
Assert.That(c1.CacheManager,
Is.Not.SameAs(c2.CacheManager));
Assert.That(c1.CacheManager.GetCache<string, string>(),
Is.Not.SameAs(c2.CacheManager.GetCache<string, string>()));
}
class ComponentOne {
public ICacheManager CacheManager { get; set; }
public ComponentOne(ICacheManager cacheManager) {
CacheManager = cacheManager;
}
}
class ComponentTwo {
public ICacheManager CacheManager { get; set; }
public ComponentTwo(ICacheManager cacheManager) {
CacheManager = cacheManager;
}
}
}
}
}

View File

@@ -1,7 +1,6 @@
using System.IO;
using System.Linq;
using NUnit.Framework;
using Orchard.Environment.Configuration;
using Orchard.Environment.FileSystems;
namespace Orchard.Tests.Environment.Configuration {

View File

@@ -3,6 +3,7 @@ using System.Linq;
using Moq;
using NUnit.Framework;
using Orchard.Environment.Configuration;
using Orchard.Environment.FileSystems;
namespace Orchard.Tests.Environment.Configuration {
[TestFixture]

View File

@@ -3,7 +3,6 @@ using System.Runtime.Serialization;
using System.Xml;
using Autofac;
using NUnit.Framework;
using Orchard.Environment.Configuration;
using Orchard.Environment.FileSystems;
using Orchard.Environment.Topology;
using Orchard.Environment.Topology.Models;

View File

@@ -125,6 +125,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Caching\CacheScopeTests.cs" />
<Compile Include="Caching\CacheTests.cs" />
<Compile Include="Commands\CommandHandlerDescriptorBuilderTests.cs" />
<Compile Include="Commands\CommandHandlerTests.cs" />

View File

@@ -16,5 +16,6 @@ namespace Orchard.Tests.Stubs {
public DateTime FutureMoment(TimeSpan span) {
return UtcNow.Add(span);
}
}
}

View File

@@ -393,7 +393,7 @@
<WebProjectProperties>
<UseIIS>False</UseIIS>
<AutoAssignPort>False</AutoAssignPort>
<DevelopmentServerPort>80</DevelopmentServerPort>
<DevelopmentServerPort>30320</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>
</IISUrl>

View File

@@ -1,14 +1,13 @@
using System;
using Orchard.Caching.Providers;
namespace Orchard.Caching {
public class AcquireContext<TKey> {
public AcquireContext(TKey key, Action<IVolatileSignal> monitor) {
public AcquireContext(TKey key, Action<IVolatileToken> monitor) {
Key = key;
IsInvalid = monitor;
Monitor = monitor;
}
public TKey Key { get; private set; }
public Action<IVolatileSignal> IsInvalid { get; private set; }
public Action<IVolatileToken> Monitor { get; private set; }
}
}

View File

@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using Orchard.Caching.Providers;
using System.Linq;
namespace Orchard.Caching {
public class Cache<TKey, TResult> : ICache<TKey, TResult> {
@@ -12,19 +12,19 @@ namespace Orchard.Caching {
public TResult Get(TKey key, Func<AcquireContext<TKey>, TResult> acquire) {
CacheEntry entry;
if (!_entries.TryGetValue(key, out entry)) {
entry = new CacheEntry { VolatileItems = new List<IVolatileSignal>() };
if (!_entries.TryGetValue(key, out entry) || entry.Tokens.Any(t => !t.IsCurrent)) {
entry = new CacheEntry { Tokens = new List<IVolatileToken>() };
var context = new AcquireContext<TKey>(key, volatileItem => entry.VolatileItems.Add(volatileItem));
var context = new AcquireContext<TKey>(key, volatileItem => entry.Tokens.Add(volatileItem));
entry.Result = acquire(context);
_entries.Add(key, entry);
_entries[key] = entry;
}
return entry.Result;
}
private class CacheEntry {
public TResult Result { get; set; }
public IList<IVolatileSignal> VolatileItems { get; set; }
public IList<IVolatileToken> Tokens { get; set; }
}
}

View File

@@ -0,0 +1,29 @@
using System;
using System.Linq;
using Autofac;
namespace Orchard.Caching {
public class CacheModule : Module {
protected override void Load(ContainerBuilder builder) {
builder.RegisterType<DefaultCacheManager>()
.As<ICacheManager>()
.InstancePerDependency();
}
protected override void AttachToComponentRegistration(Autofac.Core.IComponentRegistry componentRegistry, Autofac.Core.IComponentRegistration registration) {
var needsCacheManager = registration.Activator.LimitType
.GetConstructors()
.Any(x => x.GetParameters()
.Any(xx => xx.ParameterType == typeof(ICacheManager)));
if (needsCacheManager) {
registration.Preparing += (sender, e) => {
var parameter = new TypedParameter(
typeof(ICacheManager),
e.Context.Resolve<ICacheManager>(new TypedParameter(typeof(Type), registration.Activator.LimitType)));
e.Parameters = e.Parameters.Concat(new[] { parameter });
};
}
}
}
}

View File

@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using Castle.Core;
namespace Orchard.Caching {
public class DefaultCacheHolder : ICacheHolder {
private readonly IDictionary<CacheKey, object> _caches = new Dictionary<CacheKey, object>();
class CacheKey : Pair<Type, Pair<Type, Type>> {
public CacheKey(Type component, Type key, Type result)
: base(component, new Pair<Type, Type>(key, result)) {
}
}
public ICache<TKey, TResult> GetCache<TKey, TResult>(Type component) {
var cacheKey = new CacheKey(component, typeof(TKey), typeof(TResult));
lock (_caches) {
object value;
if (!_caches.TryGetValue(cacheKey, out value)) {
value = new Cache<TKey, TResult>();
_caches[cacheKey] = value;
}
return (ICache<TKey, TResult>)value;
}
}
}
}

View File

@@ -1,32 +1,21 @@
using System;
using System.Collections.Generic;
using Castle.Core;
namespace Orchard.Caching {
public class DefaultCacheManager : ICacheManager {
private readonly Dictionary<Pair<Type, Type>, object> _caches;
private readonly Type _component;
private readonly ICacheHolder _cacheHolder;
public DefaultCacheManager() {
_caches = new Dictionary<Pair<Type, Type>, object>();
public DefaultCacheManager(Type component, ICacheHolder cacheHolder) {
_component = component;
_cacheHolder = cacheHolder;
}
#region Implementation of ICacheManager
public ICache<TKey, TResult> GetCache<TKey, TResult>() {
return _cacheHolder.GetCache<TKey, TResult>(_component);
}
public TResult Get<TKey, TResult>(TKey key, Func<AcquireContext<TKey>, TResult> acquire) {
return GetCache<TKey, TResult>().Get(key, acquire);
}
public ICache<TKey, TResult> GetCache<TKey, TResult>() {
var cacheKey = new Pair<Type, Type>(typeof(TKey), typeof(TResult));
object value;
if (!_caches.TryGetValue(cacheKey, out value)) {
value = new Cache<TKey, TResult>();
_caches.Add(cacheKey, value);
}
return (ICache<TKey, TResult>)value;
}
#endregion
}
}

View File

@@ -0,0 +1,7 @@
using System;
namespace Orchard.Caching {
public interface ICacheHolder : ISingletonDependency {
ICache<TKey, TResult> GetCache<TKey, TResult>(Type component);
}
}

View File

@@ -1,7 +1,7 @@
using System;
namespace Orchard.Caching {
public interface ICacheManager : ISingletonDependency {
public interface ICacheManager {
TResult Get<TKey, TResult>(TKey key, Func<AcquireContext<TKey>, TResult> acquire);
ICache<TKey, TResult> GetCache<TKey, TResult>();
}

View File

@@ -0,0 +1,4 @@
namespace Orchard.Caching {
public interface IVolatileProvider : ISingletonDependency {
}
}

View File

@@ -0,0 +1,5 @@
namespace Orchard.Caching {
public interface IVolatileToken {
bool IsCurrent { get; }
}
}

View File

@@ -1,5 +0,0 @@
namespace Orchard.Caching.Providers {
public interface IVolatileProvider : IDependency {
void Enlist(IVolatileSink sink);
}
}

View File

@@ -1,5 +0,0 @@
namespace Orchard.Caching.Providers {
public interface IVolatileSignal {
IVolatileProvider Provider { get; set; }
}
}

View File

@@ -1,5 +0,0 @@
namespace Orchard.Caching.Providers {
public interface IVolatileSink {
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Runtime.Serialization;
namespace Orchard.Caching {
public class Weak<T> : WeakReference {
public Weak(T target)
: base(target) {
}
public Weak(T target, bool trackResurrection)
: base(target, trackResurrection) {
}
protected Weak(SerializationInfo info, StreamingContext context)
: base(info, context) {
}
public new T Target {
get { return (T)base.Target; }
set { base.Target = value; }
}
}
}

View File

@@ -24,7 +24,7 @@ namespace Orchard.Environment.Extensions.Folders {
private readonly ICacheManager _cacheManager;
private readonly IVirtualPathProvider _virtualPathProvider;
public ExtensionFolders(
protected ExtensionFolders(
IEnumerable<string> paths,
string manifestName,
bool manifestIsOptional,
@@ -39,28 +39,39 @@ namespace Orchard.Environment.Extensions.Folders {
}
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
var virtualPaths = _cacheManager.Get("", ctx => {
var x = 5;
return new[] { "hello" };
});
var list = new List<ExtensionDescriptor>();
foreach (var virtualPath in virtualPaths) {
list.Add(GetExtensionDescriptor(virtualPath));
foreach (var locationPath in _paths) {
var subfolderPaths = _cacheManager.Get(locationPath, ctx => {
ctx.Monitor(_virtualPathProvider.WhenPathChanges(ctx.Key));
return _virtualPathProvider.GetSubfolderPaths(ctx.Key);
});
foreach (var subfolderPath in subfolderPaths) {
var extensionName = Path.GetFileName(subfolderPath.TrimEnd('/', '\\'));
var manifestPath = Path.Combine(subfolderPath, _manifestName);
var descriptor = GetExtensionDescriptor(locationPath, extensionName, manifestPath);
if (descriptor != null)
list.Add(descriptor);
}
}
return list;
}
ExtensionDescriptor GetExtensionDescriptor(string virtualPath) {
return _cacheManager.Get(virtualPath, context => {
ExtensionDescriptor GetExtensionDescriptor(string locationPath, string extensionName, string manifestPath) {
return _cacheManager.Get(manifestPath, context => {
context.IsInvalid(_virtualPathProvider.WhenPathChanges(virtualPath));
context.Monitor(_virtualPathProvider.WhenPathChanges(manifestPath));
var text = _virtualPathProvider.ReadAllText(virtualPath);
var manifestText = _virtualPathProvider.ReadAllText(manifestPath);
if (manifestText == null) {
if (_manifestIsOptional) {
manifestText = string.Format("name: {0}", extensionName);
}
else {
return null;
}
}
var parseResult = ParseManifest(text);
return GetDescriptorForExtension(parseResult.Name, parseResult);
return GetDescriptorForExtension(locationPath, extensionName, ParseManifest(manifestText));
});
}
@@ -78,52 +89,29 @@ namespace Orchard.Environment.Extensions.Folders {
}
public ParseResult ParseManifest(string name) {
foreach (var path in _paths) {
if (!Directory.Exists(PathHelpers.GetPhysicalPath(path)))
continue;
var extensionDirectoryPath = Path.Combine(PathHelpers.GetPhysicalPath(path), name);
if (!Directory.Exists(PathHelpers.GetPhysicalPath(extensionDirectoryPath)))
continue;
var extensionManifestPath = Path.Combine(extensionDirectoryPath, _manifestName);
if (File.Exists(extensionManifestPath)) {
var yamlStream = YamlParser.Load(extensionManifestPath);
return new ParseResult {
Location = path,
Name = name,
YamlDocument = yamlStream.Documents.Single()
};
}
if (_manifestIsOptional) {
var yamlInput = new TextInput(string.Format("name: {0}", name));
var parser = new YamlParser();
bool success;
var yamlStream = parser.ParseYamlStream(yamlInput, out success);
return new ParseResult {
Location = path,
Name = name,
YamlDocument = yamlStream.Documents.Single()
};
}
bool success;
var yamlStream = new YamlParser().ParseYamlStream(new TextInput(name), out success);
if (yamlStream == null || !success) {
return null;
}
return null;
return new ParseResult {
Name = name,
YamlDocument = yamlStream.Documents.Single()
};
}
private ExtensionDescriptor GetDescriptorForExtension(string name, ParseResult parseResult) {
private ExtensionDescriptor GetDescriptorForExtension(string locationPath, string extensionName, ParseResult parseResult) {
var mapping = (Mapping)parseResult.YamlDocument.Root;
var fields = mapping.Entities
.Where(x => x.Key is Scalar)
.ToDictionary(x => ((Scalar)x.Key).Text, x => x.Value);
var extensionDescriptor = new ExtensionDescriptor {
Location = parseResult.Location,
Name = name,
Location = locationPath,
Name = extensionName,
ExtensionType = _extensionType,
DisplayName = GetValue(fields, "name") ?? name,
DisplayName = GetValue(fields, "name") ?? extensionName,
Description = GetValue(fields, "description"),
Version = GetValue(fields, "version"),
OrchardVersion = GetValue(fields, "orchardversion"),

View File

@@ -1,11 +1,9 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web.Hosting;
using Orchard.Environment.FileSystems;
namespace Orchard.Environment.Configuration {
namespace Orchard.Environment.FileSystems {
public class AppDataFolder : IAppDataFolder {
protected string _basePath;
@@ -42,9 +40,9 @@ namespace Orchard.Environment.Configuration {
var files = Directory.GetFiles(directoryPath);
return files.Select(file => {
var fileName = Path.GetFileName(file);
return Path.Combine(path, fileName);
});
var fileName = Path.GetFileName(file);
return Path.Combine(path, fileName);
});
}
public IEnumerable<string> ListDirectories(string path) {
@@ -55,9 +53,9 @@ namespace Orchard.Environment.Configuration {
var files = Directory.GetDirectories(directoryPath);
return files.Select(file => {
var fileName = Path.GetFileName(file);
return Path.Combine(path, fileName);
});
var fileName = Path.GetFileName(file);
return Path.Combine(path, fileName);
});
}
public string CreateDirectory(string path) {
@@ -74,5 +72,6 @@ namespace Orchard.Environment.Configuration {
public string MapPath(string path) {
return Path.Combine(_basePath, path);
}
}
}
}

View File

@@ -1,54 +1,127 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web.Caching;
using System.Web.Hosting;
using Orchard.Caching.Providers;
using Orchard.Caching;
using Orchard.Services;
namespace Orchard.Environment.FileSystems {
public class DefaultVirtualPathProvider : IVirtualPathProvider {
private readonly IClock _clock;
private readonly IList<IVolatileSink> _sinks = new List<IVolatileSink>();
//private string _cachePrefix = Guid.NewGuid().ToString("n");
private readonly Thunk _thunk;
private readonly string _prefix = Guid.NewGuid().ToString("n");
private readonly IDictionary<string, Weak<Token>> _tokens = new Dictionary<string, Weak<Token>>();
public DefaultVirtualPathProvider(IClock clock) {
_clock = clock;
_thunk = new Thunk(this);
}
public IEnumerable<string> GetSubfolderPaths(string virtualPath) {
if (!HostingEnvironment.VirtualPathProvider.DirectoryExists(virtualPath))
return Enumerable.Empty<string>();
return HostingEnvironment.VirtualPathProvider
.GetDirectory(virtualPath)
.Directories.OfType<VirtualDirectory>()
.Select(d => d.VirtualPath)
.ToArray();
}
public string ReadAllText(string virtualPath) {
if (!HostingEnvironment.VirtualPathProvider.FileExists(virtualPath))
return null;
using (var stream = VirtualPathProvider.OpenFile(virtualPath)) {
using (var reader = new StreamReader(stream)) {
return reader.ReadToEnd();
}
}
//var cd = HostingEnvironment.VirtualPathProvider.. .GetCacheDependency(virtualPath, null, _clock.UtcNow);
//HostingEnvironment.Cache.Add(
// _cachePrefix + virtualPath,
// virtualPath,
// cd,
// NoAbsoluteExpiration,
// );
}
public IVolatileSignal WhenPathChanges(string virtualPath) {
return new VirtualPathSignal(this, virtualPath);
public IVolatileToken WhenPathChanges(string virtualPath) {
var token = BindToken(virtualPath);
BindSignal(virtualPath);
return token;
}
private Token BindToken(string virtualPath) {
lock (_tokens) {
Weak<Token> weak;
if (!_tokens.TryGetValue(virtualPath, out weak)) {
weak = new Weak<Token>(new Token(virtualPath));
_tokens[virtualPath] = weak;
}
class VirtualPathSignal : IVolatileSignal {
private readonly string _virtualPath;
var token = weak.Target;
if (token == null) {
token = new Token(virtualPath);
weak.Target = token;
}
public VirtualPathSignal(DefaultVirtualPathProvider provider, string virtualPath) {
_virtualPath = virtualPath;
Provider = provider;
return token;
}
}
private Token DetachToken(string virtualPath) {
lock (_tokens) {
Weak<Token> weak;
if (!_tokens.TryGetValue(virtualPath, out weak)) {
return null;
}
var token = weak.Target;
weak.Target = null;
return token;
}
}
private void BindSignal(string virtualPath) {
var cacheDependency = HostingEnvironment.VirtualPathProvider.GetCacheDependency(
virtualPath,
new[] { virtualPath },
_clock.UtcNow);
HostingEnvironment.Cache.Add(
_prefix + virtualPath,
virtualPath,
cacheDependency,
Cache.NoAbsoluteExpiration,
Cache.NoSlidingExpiration,
CacheItemPriority.NotRemovable,
_thunk.Signal);
}
public void Signal(string key, object value, CacheItemRemovedReason reason) {
var virtualPath = Convert.ToString(value);
var token = DetachToken(virtualPath);
if (token != null)
token.IsCurrent = false;
}
public class Token : IVolatileToken {
public Token(string virtualPath) {
IsCurrent = true;
VirtualPath = virtualPath;
}
public bool IsCurrent { get; set; }
public string VirtualPath { get; private set; }
}
class Thunk {
private readonly Weak<DefaultVirtualPathProvider> _weak;
public Thunk(DefaultVirtualPathProvider provider) {
_weak = new Weak<DefaultVirtualPathProvider>(provider);
}
public IVolatileProvider Provider { get; set; }
}
public void Enlist(IVolatileSink sink) {
_sinks.Add(sink);
public void Signal(string key, object value, CacheItemRemovedReason reason) {
var provider = _weak.Target;
if (provider != null)
provider.Signal(key, value, reason);
}
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Orchard.Caching;
namespace Orchard.Environment.FileSystems {
/// <summary>
@@ -6,7 +7,7 @@ namespace Orchard.Environment.FileSystems {
/// Expected to work on physical filesystem, but decouples core
/// system from web hosting apis
/// </summary>
public interface IAppDataFolder {
public interface IAppDataFolder : IVolatileProvider {
IEnumerable<string> ListFiles(string path);
IEnumerable<string> ListDirectories(string path);

View File

@@ -1,9 +1,11 @@
using Orchard.Caching.Providers;
using System.Collections.Generic;
using Orchard.Caching;
namespace Orchard.Environment.FileSystems {
public interface IVirtualPathProvider : IVolatileProvider {
IVolatileSignal WhenPathChanges(string path);
IEnumerable<string> GetSubfolderPaths(string virtualPath);
string ReadAllText(string virtualPath);
IVolatileToken WhenPathChanges(string path);
}
}
}

View File

@@ -5,6 +5,7 @@ using System.Web.Hosting;
using Autofac;
using Autofac.Configuration;
using Autofac.Integration.Web;
using Orchard.Caching;
using Orchard.Environment.AutofacUtil;
using Orchard.Environment.Configuration;
using Orchard.Environment.Extensions;
@@ -15,6 +16,7 @@ using Orchard.Environment.ShellBuilders;
using Orchard.Environment.Topology;
using Orchard.Events;
using Orchard.Logging;
using Orchard.Services;
namespace Orchard.Environment {
public static class OrchardStarter {
@@ -22,10 +24,15 @@ namespace Orchard.Environment {
var builder = new ContainerBuilder();
builder.RegisterModule(new LoggingModule());
builder.RegisterModule(new EventsModule());
builder.RegisterModule(new CacheModule());
// a single default host implementation is needed for bootstrapping a web app domain
builder.RegisterType<DefaultOrchardEventBus>().As<IEventBus>().SingleInstance();
builder.RegisterType<AppDataFolder>().As<IAppDataFolder>().SingleInstance();
builder.RegisterType<DefaultCacheHolder>().As<ICacheHolder>().SingleInstance();
RegisterVolatileProvider<DefaultVirtualPathProvider, IVirtualPathProvider>(builder);
RegisterVolatileProvider<AppDataFolder, IAppDataFolder>(builder);
RegisterVolatileProvider<Clock, IClock>(builder);
builder.RegisterType<DefaultOrchardHost>().As<IOrchardHost>().As<IEventHandler>().SingleInstance();
{
@@ -92,6 +99,13 @@ namespace Orchard.Environment {
return builder.Build();
}
private static void RegisterVolatileProvider<TRegister, TService>(ContainerBuilder builder) where TService : IVolatileProvider {
builder.RegisterType<TRegister>()
.As<TService>()
.As<IVolatileProvider>()
.SingleInstance();
}
public static IOrchardHost CreateHost(Action<ContainerBuilder> registrations) {
var container = CreateHostContainer(registrations);
return container.Resolve<IOrchardHost>();

View File

@@ -5,6 +5,7 @@
public interface ISingletonDependency : IDependency {
}
public interface ITransientDependency : IDependency {
}

View File

@@ -145,15 +145,18 @@
<ItemGroup>
<Compile Include="Caching\AcquireContext.cs" />
<Compile Include="Caching\Cache.cs" />
<Compile Include="Caching\CacheModule.cs" />
<Compile Include="Caching\DefaultCacheHolder.cs" />
<Compile Include="Caching\DefaultCacheManager.cs" />
<Compile Include="Caching\Providers\IVolatileSink.cs" />
<Compile Include="Caching\ICacheHolder.cs" />
<Compile Include="Caching\Weak.cs" />
<Compile Include="Environment\FileSystems\DefaultVirtualPathProvider.cs" />
<Compile Include="Environment\FileSystems\IAppDataFolder.cs" />
<Compile Include="Environment\FileSystems\IVirtualPathProvider.cs" />
<Compile Include="Caching\ICache.cs" />
<Compile Include="Caching\ICacheManager.cs" />
<Compile Include="Caching\Providers\IVolatileSignal.cs" />
<Compile Include="Caching\Providers\IVolatileProvider.cs" />
<Compile Include="Caching\IVolatileToken.cs" />
<Compile Include="Caching\IVolatileProvider.cs" />
<Compile Include="Commands\CommandParameters.cs" />
<Compile Include="Commands\CommandDescriptor.cs" />
<Compile Include="Commands\CommandHandlerDescriptor.cs" />

View File

@@ -1,13 +1,15 @@
using System;
using Orchard.Caching;
namespace Orchard.Services {
public interface IClock : IDependency {
public interface IClock : IVolatileProvider {
DateTime UtcNow { get; }
}
public class Clock : IClock {
public DateTime UtcNow {
get { return DateTime.Now; }
get { return DateTime.UtcNow; }
}
}
}