PERF: Move async token monitoring to a service interface

Update UT

--HG--
branch : 1.x
This commit is contained in:
Renaud Paquay
2011-05-29 13:58:06 -07:00
parent 234375704a
commit 1fd64b705d
18 changed files with 143 additions and 73 deletions

View File

@@ -50,6 +50,7 @@ namespace Orchard.Tests.Modules.CodeGeneration.Commands {
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
builder.RegisterType<SchemaCommandGenerator>().As<ISchemaCommandGenerator>();
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
builder.RegisterType<StubHostEnvironment>().As<IHostEnvironment>();
_container = builder.Build();

View File

@@ -88,6 +88,7 @@ namespace Orchard.Tests.Modules.Migrations {
builder.RegisterType<SchemaCommandGenerator>().As<ISchemaCommandGenerator>();
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
builder.RegisterType<StubHostEnvironment>().As<IHostEnvironment>();
_session = _sessionFactory.OpenSession();

View File

@@ -31,6 +31,7 @@ namespace Orchard.Tests.Modules.Packaging.Services {
builder.RegisterType<FolderUpdater>().As<IFolderUpdater>();
builder.RegisterInstance(new Mock<INotifier>().Object);
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
_mockedVirtualPathProvider = new Mock<IVirtualPathProvider>();
builder.RegisterInstance(_mockedVirtualPathProvider.Object).As<IVirtualPathProvider>();

View File

@@ -31,6 +31,7 @@ namespace Orchard.Tests.Modules.Packaging.Services {
builder.RegisterType<FolderUpdater>().As<IFolderUpdater>();
builder.RegisterInstance(new Mock<INotifier>().Object);
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
_mockedVirtualPathProvider = new Mock<IVirtualPathProvider>();
builder.RegisterInstance(_mockedVirtualPathProvider.Object).As<IVirtualPathProvider>();

View File

@@ -50,6 +50,7 @@ namespace Orchard.Tests.Modules.Recipes.RecipeHandlers {
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
builder.RegisterType<FeatureManager>().As<IFeatureManager>();
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
builder.RegisterType<ShellDescriptorManager>().As<IShellDescriptorManager>().SingleInstance();
builder.RegisterType<StubDataMigrationManager>().As<IDataMigrationManager>();
builder.RegisterType<StubPackagingSourceManager>().As<IPackagingSourceManager>();

View File

@@ -53,6 +53,7 @@ namespace Orchard.Tests.Modules.Recipes.RecipeHandlers {
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
builder.RegisterType<FeatureManager>().As<IFeatureManager>();
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
builder.RegisterType<ShellDescriptorManager>().As<IShellDescriptorManager>().SingleInstance();
builder.RegisterType<ModuleRecipeHandlerTest.StubDataMigrationManager>().As<IDataMigrationManager>();
builder.RegisterType<ModuleRecipeHandlerTest.StubPackagingSourceManager>().As<IPackagingSourceManager>();

View File

@@ -73,6 +73,7 @@ namespace Orchard.Tests.Modules.Recipes.Services {
builder.RegisterType<StubAppDataFolder>().As<IAppDataFolder>();
builder.RegisterType<StubClock>().As<IClock>();
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
builder.RegisterInstance(_folders).As<IExtensionFolders>();
builder.RegisterType<Environment.Extensions.ExtensionManagerTests.StubLoaders>().As<IExtensionLoader>();
builder.RegisterType<RecipeParser>().As<IRecipeParser>();

View File

@@ -68,6 +68,7 @@ namespace Orchard.Tests.DataMigration {
builder.RegisterType<DataMigrationManager>().As<IDataMigrationManager>();
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
_session = _sessionFactory.OpenSession();
builder.RegisterInstance(new DefaultContentManagerTests.TestSessionLocator(_session)).As<ISessionLocator>();
foreach(var type in dataMigrations) {

View File

@@ -27,6 +27,7 @@ namespace Orchard.Tests.Environment.Extensions {
builder.RegisterInstance(_folders).As<IExtensionFolders>();
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
_container = builder.Build();
_manager = _container.Resolve<IExtensionManager>();
@@ -360,7 +361,7 @@ Features:
Description: Contains the Phi type.
");
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
var testFeature = extensionManager.AvailableExtensions()
.SelectMany(x => x.Features);
@@ -386,7 +387,7 @@ Features:
Description: Contains the Phi type.
");
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
var testFeature = extensionManager.AvailableExtensions()
.SelectMany(x => x.Features);
@@ -415,7 +416,7 @@ Features:
Description: Contains the Phi type.
");
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
var testFeature = extensionManager.AvailableExtensions()
.SelectMany(x => x.Features)
.Single(x => x.Id == "TestFeature");
@@ -445,7 +446,7 @@ Features:
Description: Contains the Phi type.
");
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
var testFeature = extensionManager.AvailableExtensions()
.SelectMany(x => x.Features)
.Single(x => x.Id == "TestFeature");
@@ -473,7 +474,7 @@ Features:
Description: Contains the Phi type.
");
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
var testModule = extensionManager.AvailableExtensions()
.SelectMany(x => x.Features)
.Single(x => x.Id == "TestModule");
@@ -497,7 +498,7 @@ Version: 1.0.3
OrchardVersion: 1
");
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
var minimalisticModule = extensionManager.AvailableExtensions().Single(x => x.Id == "Minimalistic");
Assert.That(minimalisticModule.Features.Count(), Is.EqualTo(1));
@@ -516,7 +517,7 @@ Version: 1.0.3
OrchardVersion: 1
");
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
var minimalisticModule = extensionManager.AvailableExtensions().Single(x => x.Id == "Minimalistic");
Assert.That(minimalisticModule.Features.Count(), Is.EqualTo(1));

View File

@@ -28,6 +28,7 @@ namespace Orchard.Tests.Environment.Extensions {
builder.RegisterInstance(_folders).As<IExtensionFolders>();
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
_container = builder.Build();
_manager = _container.Resolve<IExtensionManager>();
@@ -283,7 +284,7 @@ Features:
Description: Contains the Phi type.
");
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
var testFeature = extensionManager.AvailableExtensions()
.SelectMany(x => x.Features);
@@ -309,7 +310,7 @@ Features:
Description: Contains the Phi type.
");
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
var testFeature = extensionManager.AvailableExtensions()
.SelectMany(x => x.Features);
@@ -346,7 +347,7 @@ Features:
Description: Contains the Phi type.
");
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
var testFeature = extensionManager.AvailableExtensions()
.SelectMany(x => x.Features)
.Single(x => x.Id == "TestFeature");
@@ -376,7 +377,7 @@ Features:
Description: Contains the Phi type.
");
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
var testFeature = extensionManager.AvailableExtensions()
.SelectMany(x => x.Features)
.Single(x => x.Id == "TestFeature");
@@ -404,7 +405,7 @@ Features:
Description: Contains the Phi type.
");
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
var testModule = extensionManager.AvailableExtensions()
.SelectMany(x => x.Features)
.Single(x => x.Id == "TestModule");
@@ -428,7 +429,7 @@ Version: 1.0.3
OrchardVersion: 1
");
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
var minimalisticModule = extensionManager.AvailableExtensions().Single(x => x.Id == "Minimalistic");
Assert.That(minimalisticModule.Features.Count(), Is.EqualTo(1));
@@ -464,7 +465,7 @@ Features:
Dependencies: Beta
");
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
var features = extensionManager.AvailableFeatures();
Assert.That(features.Aggregate("<", (a, b) => a + b.Id + "<"), Is.EqualTo("<Beta<Gamma<Alpha<"));
}
@@ -504,7 +505,7 @@ Version: 1.0.3
OrchardVersion: 1
");
IExtensionManager extensionManager = new ExtensionManager(new[] { moduleExtensionFolder, themeExtensionFolder }, new[] { extensionLoader }, new StubCacheManager());
IExtensionManager extensionManager = new ExtensionManager(new[] { moduleExtensionFolder, themeExtensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
var features = extensionManager.AvailableFeatures();
Assert.That(features.Count(), Is.EqualTo(4));
}
@@ -538,7 +539,7 @@ OrchardVersion: 1{1}{2}",
}
private static void AssertFeaturesAreInOrder(IEnumerable<StubFolders> folders, StubLoaders loader, string expectedOrder) {
var extensionManager = new ExtensionManager(folders, new[] { loader }, new StubCacheManager());
var extensionManager = new ExtensionManager(folders, new[] { loader }, new StubCacheManager(), new StubAsyncTokenProvider());
var features = extensionManager.AvailableFeatures();
Assert.That(features.Aggregate("<", (a, b) => a + b.Id + "<"), Is.EqualTo(expectedOrder));
}

View File

@@ -39,6 +39,7 @@ namespace Orchard.Tests.Environment.Features {
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
builder.RegisterType<FeatureManager>().As<IFeatureManager>();
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
builder.RegisterType<ShellDescriptorManager>().As<IShellDescriptorManager>().SingleInstance();
builder.RegisterType<ShellStateManager>().As<IShellStateManager>().SingleInstance();
builder.RegisterType<StubEventBus>().As<IEventBus>().SingleInstance();

View File

@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Orchard.Caching;
namespace Orchard.Tests.Stubs {
@@ -16,4 +18,21 @@ namespace Orchard.Tests.Stubs {
return _defaultCacheManager.GetCache<TKey, TResult>();
}
}
public class StubAsyncTokenProvider : IAsyncTokenProvider {
public IVolatileToken GetToken(Action<Action<IVolatileToken>> task) {
var tokens = new List<IVolatileToken>();
task(tokens.Add);
return new Token(tokens);
}
public class Token : IVolatileToken {
private readonly List<IVolatileToken> _tokens;
public Token(List<IVolatileToken> tokens) {
_tokens = tokens;
}
public bool IsCurrent { get { return _tokens.All(t => t.IsCurrent); } }
}
}
}

View File

@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Orchard.Logging;
namespace Orchard.Caching {
public class DefaultAsyncTokenProvider : IAsyncTokenProvider {
public DefaultAsyncTokenProvider() {
Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }
public IVolatileToken GetToken(Action<Action<IVolatileToken>> task) {
var token = new AsyncVolativeToken(task, Logger);
token.QueueWorkItem();
return token;
}
public class AsyncVolativeToken : IVolatileToken {
private readonly Action<Action<IVolatileToken>> _task;
private readonly List<IVolatileToken> _taskTokens = new List<IVolatileToken>();
private volatile Exception _taskException;
private volatile bool _isTaskFinished;
public AsyncVolativeToken(Action<Action<IVolatileToken>> task, ILogger logger) {
_task = task;
Logger = logger;
}
public ILogger Logger { get; set; }
public void QueueWorkItem() {
// Start a work item to collect tokens in our internal array
ThreadPool.QueueUserWorkItem((state) => {
try {
_task(token => _taskTokens.Add(token));
}
catch (Exception e) {
Logger.Error(e, "Error while monitoring extension files. Assuming extensions are not current.");
_taskException = e;
}
finally {
_isTaskFinished = true;
}
});
}
public bool IsCurrent {
get {
// We are current until the task has finished
if (_taskException != null) {
return false;
}
if (_isTaskFinished) {
return _taskTokens.All(t => t.IsCurrent);
}
return true;
}
}
}
}
}

View File

@@ -0,0 +1,7 @@
using System;
namespace Orchard.Caching {
public interface IAsyncTokenProvider {
IVolatileToken GetToken(Action<Action<IVolatileToken>> task);
}
}

View File

@@ -13,14 +13,21 @@ using Orchard.Utility.Extensions;
namespace Orchard.Environment.Extensions {
public class ExtensionManager : IExtensionManager {
private readonly IEnumerable<IExtensionFolders> _folders;
private readonly IAsyncTokenProvider _asyncTokenProvider;
private readonly ICacheManager _cacheManager;
private readonly IEnumerable<IExtensionLoader> _loaders;
public Localizer T { get; set; }
public ILogger Logger { get; set; }
public ExtensionManager(IEnumerable<IExtensionFolders> folders, IEnumerable<IExtensionLoader> loaders, ICacheManager cacheManager) {
public ExtensionManager(
IEnumerable<IExtensionFolders> folders,
IEnumerable<IExtensionLoader> loaders,
ICacheManager cacheManager,
IAsyncTokenProvider asyncTokenProvider) {
_folders = folders;
_asyncTokenProvider = asyncTokenProvider;
_cacheManager = cacheManager;
_loaders = loaders.OrderBy(x => x.Order).ToArray();
T = NullLocalizer.Instance;
@@ -38,7 +45,7 @@ namespace Orchard.Environment.Extensions {
}
public IEnumerable<FeatureDescriptor> AvailableFeatures() {
return _cacheManager.Get("...", ctx =>
return _cacheManager.Get("...", ctx =>
AvailableExtensions().SelectMany(ext => ext.Features).OrderByDependenciesAndPriorities(HasDependency, GetPriority).ToReadOnlyCollection());
}
@@ -58,7 +65,7 @@ namespace Orchard.Environment.Extensions {
// Themes implicitly depend on modules to ensure build and override ordering
return true;
}
if (DefaultExtensionTypes.IsTheme(subject.Extension.ExtensionType)) {
// Theme depends on another if it is its base theme
return item.Extension.BaseTheme == subject.Id;
@@ -91,9 +98,11 @@ namespace Orchard.Environment.Extensions {
extensionEntry = _cacheManager.Get(extensionId, ctx => {
var entry = BuildEntry(extensionDescriptor);
if (entry != null) {
foreach (var loader in _loaders) {
loader.Monitor(entry.Descriptor, (token) => ctx.Monitor(token));
}
ctx.Monitor(_asyncTokenProvider.GetToken(monitor => {
foreach (var loader in _loaders) {
loader.Monitor(entry.Descriptor, token => monitor(token));
}
}));
}
return entry;
});
@@ -134,7 +143,7 @@ namespace Orchard.Environment.Extensions {
}
return extensionId;
}
private ExtensionEntry BuildEntry(ExtensionDescriptor descriptor) {
foreach (var loader in _loaders) {
ExtensionEntry entry = loader.Load(descriptor);

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Orchard.Caching;
using Orchard.Environment.Extensions.Loaders;
using Orchard.Environment.Extensions.Models;
@@ -11,14 +10,18 @@ using Orchard.Logging;
namespace Orchard.Environment.Extensions {
public class ExtensionMonitoringCoordinator : IExtensionMonitoringCoordinator {
private readonly IVirtualPathMonitor _virtualPathMonitor;
private readonly IAsyncTokenProvider _asyncTokenProvider;
private readonly IExtensionManager _extensionManager;
private readonly IEnumerable<IExtensionLoader> _loaders;
public ExtensionMonitoringCoordinator(IVirtualPathMonitor virtualPathMonitor,
public ExtensionMonitoringCoordinator(
IVirtualPathMonitor virtualPathMonitor,
IAsyncTokenProvider asyncTokenProvider,
IExtensionManager extensionManager,
IEnumerable<IExtensionLoader> loaders) {
_virtualPathMonitor = virtualPathMonitor;
_asyncTokenProvider = asyncTokenProvider;
_extensionManager = extensionManager;
_loaders = loaders;
@@ -33,11 +36,8 @@ namespace Orchard.Environment.Extensions {
if (Disabled)
return;
//PREF: Monitor extensions asynchronously. IsCurrent will be 'true'
// until all tokens are collected by the work function.
var token = new AsyncVolativeToken(MonitorExtensionsWork, Logger);
monitor(token);
token.QueueWorkItem();
//PERF: Monitor extensions asynchronously.
monitor(_asyncTokenProvider.GetToken(MonitorExtensionsWork));
}
public void MonitorExtensionsWork(Action<IVolatileToken> monitor) {
@@ -55,48 +55,5 @@ namespace Orchard.Environment.Extensions {
}
Logger.Information("Done monitoring extension files...");
}
public class AsyncVolativeToken : IVolatileToken {
private readonly Action<Action<IVolatileToken>> _task;
private readonly List<IVolatileToken> _taskTokens = new List<IVolatileToken>();
private volatile Exception _taskException;
private volatile bool _isTaskFinished;
public AsyncVolativeToken(Action<Action<IVolatileToken>> task, ILogger logger) {
_task = task;
Logger = logger;
}
public ILogger Logger { get; set; }
public void QueueWorkItem() {
// Start a work item to collect tokens in our internal array
ThreadPool.QueueUserWorkItem((state) => {
try {
_task(token => _taskTokens.Add(token));
}
catch (Exception e) {
Logger.Error(e, "Error while monitoring extension files. Assuming extensions are not current.");
_taskException = e;
}
finally {
_isTaskFinished = true;
}
});
}
public bool IsCurrent {
get {
// We are current until the task has finished
if (_taskException != null) {
return false;
}
if (_isTaskFinished) {
return _taskTokens.All(t => t.IsCurrent);
}
return true;
}
}
}
}
}

View File

@@ -39,6 +39,7 @@ namespace Orchard.Environment {
// a single default host implementation is needed for bootstrapping a web app domain
builder.RegisterType<DefaultOrchardEventBus>().As<IEventBus>().SingleInstance();
builder.RegisterType<DefaultCacheHolder>().As<ICacheHolder>().SingleInstance();
builder.RegisterType<DefaultAsyncTokenProvider>().As<IAsyncTokenProvider>().SingleInstance();
builder.RegisterType<DefaultHostEnvironment>().As<IHostEnvironment>().SingleInstance();
builder.RegisterType<DefaultHostLocalRestart>().As<IHostLocalRestart>().SingleInstance();
builder.RegisterType<DefaultBuildManager>().As<IBuildManager>().SingleInstance();

View File

@@ -175,7 +175,9 @@
<Compile Include="DisplayManagement\Shapes\ShapeDebugView.cs" />
<Compile Include="DisplayManagement\Shapes\ITagBuilderFactory.cs" />
<Compile Include="Environment\CollectionOrderModule.cs" />
<Compile Include="Caching\DefaultAsyncTokenProvider.cs" />
<Compile Include="Environment\Extensions\ExtensionMonitoringCoordinator.cs" />
<Compile Include="Caching\IAsyncTokenProvider.cs" />
<Compile Include="Environment\Extensions\IExtensionMonitoringCoordinator.cs" />
<Compile Include="Environment\Extensions\OrchardSuppressDependencyAttribute.cs" />
<Compile Include="Environment\Features\IFeatureManager.cs" />