Incremental work towards cache/volatile system

--HG--
branch : dev
This commit is contained in:
Louis DeJardin
2010-05-14 22:30:16 -07:00
parent fba838f366
commit c138cc996d
40 changed files with 396 additions and 217 deletions

View File

@@ -18,7 +18,18 @@ namespace Orchard.Profile.Tests {
[Given(@"I am logged in")]
public void GivenIAmLoggedIn() {
DoRequest("/Users/Account/LogOn", "userNameOrEmail=admin&password=profiling-secret&rememberMe=false");
DoRequest("/Users/Account/LogOn");
const string requestVerificationTokenName = "__RequestVerificationToken";
const string valueMarker = "value=\"";
var tokenIndex = _text.IndexOf(requestVerificationTokenName);
var valueIndex = _text.IndexOf(valueMarker, tokenIndex);
var valueStart = valueIndex + valueMarker.Length;
var valueEnd = _text.IndexOf("\"", valueStart);
var requestVerificationTokenValue = _text.Substring(valueStart, valueEnd - valueStart);
DoRequest("/Users/Account/LogOn", "userNameOrEmail=admin&password=profiling-secret&rememberMe=false&" + requestVerificationTokenName + "=" + requestVerificationTokenValue);
}
[When(@"I go to ""(.*)""")]

View File

@@ -3,6 +3,12 @@
As a developer
I want to generate a fixed number of repeatable requests
Scenario: Warmup
Given I am logged in
When I go to "/admin"
When I go to "/blog0"
When I go to "/"
Scenario: Dashboard
Given I am logged in
When I go to "/admin" 40 times

View File

@@ -2,7 +2,7 @@
// <auto-generated>
// This code was generated by SpecFlow (http://www.specflow.org/).
// SpecFlow Version:1.2.0.0
// Runtime Version:2.0.50727.3603
// Runtime Version:2.0.50727.4927
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -51,15 +51,34 @@ namespace Orchard.Profile.Tests
}
[NUnit.Framework.TestAttribute()]
[NUnit.Framework.DescriptionAttribute("Dashboard")]
public virtual void Dashboard()
[NUnit.Framework.DescriptionAttribute("Warmup")]
public virtual void Warmup()
{
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Dashboard", ((string[])(null)));
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Warmup", ((string[])(null)));
#line 6
this.ScenarioSetup(scenarioInfo);
#line 7
testRunner.Given("I am logged in");
#line 8
testRunner.When("I go to \"/admin\"");
#line 9
testRunner.When("I go to \"/blog0\"");
#line 10
testRunner.When("I go to \"/\"");
#line hidden
testRunner.CollectScenarioErrors();
}
[NUnit.Framework.TestAttribute()]
[NUnit.Framework.DescriptionAttribute("Dashboard")]
public virtual void Dashboard()
{
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Dashboard", ((string[])(null)));
#line 12
this.ScenarioSetup(scenarioInfo);
#line 13
testRunner.Given("I am logged in");
#line 14
testRunner.When("I go to \"/admin\" 40 times");
#line hidden
testRunner.CollectScenarioErrors();
@@ -70,19 +89,19 @@ this.ScenarioSetup(scenarioInfo);
public virtual void HittingBlogs()
{
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Hitting blogs", ((string[])(null)));
#line 10
this.ScenarioSetup(scenarioInfo);
#line 11
testRunner.Given("I am logged in");
#line 12
testRunner.When("I go to \"/blog0\" 10 times");
#line 13
testRunner.When("I go to \"/blog1\" 10 times");
#line 14
testRunner.When("I go to \"/blog2\" 10 times");
#line 15
testRunner.When("I go to \"/blog3\" 10 times");
#line 16
this.ScenarioSetup(scenarioInfo);
#line 17
testRunner.Given("I am logged in");
#line 18
testRunner.When("I go to \"/blog0\" 10 times");
#line 19
testRunner.When("I go to \"/blog1\" 10 times");
#line 20
testRunner.When("I go to \"/blog2\" 10 times");
#line 21
testRunner.When("I go to \"/blog3\" 10 times");
#line 22
testRunner.When("I go to \"/blog4\" 10 times");
#line hidden
testRunner.CollectScenarioErrors();
@@ -93,11 +112,11 @@ this.ScenarioSetup(scenarioInfo);
public virtual void HittingHomePage()
{
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Hitting home page", ((string[])(null)));
#line 18
#line 24
this.ScenarioSetup(scenarioInfo);
#line 19
#line 25
testRunner.Given("I am logged in");
#line 20
#line 26
testRunner.When("I go to \"/\" 40 times");
#line hidden
testRunner.CollectScenarioErrors();

View File

@@ -1,6 +1,3 @@
help commands
setup /SiteName:Profiling /AdminUsername:admin /AdminPassword:profiling-secret /DatabaseProvider:SQLite /EnabledFeatures:Orchard.Framework,Common,Dashboard,Feeds,HomePage,Navigation,Scheduling,Settings,XmlRpc,Orchard.Users,Orchard.Roles,TinyMce,Orchard.Modules,Orchard.Themes,Orchard.MultiTenancy,Orchard.Pages,Orchard.Blogs,Orchard.Comments,Futures.Widgets,Orchard.Media,Orchard.Tags,Orchard.DevTools
help commands
tenant list
feature list
setup /SiteName:Profiling /AdminUsername:admin /AdminPassword:profiling-secret /DatabaseProvider:SQLite /EnabledFeatures:Orchard.Framework,Common,Dashboard,Feeds,HomePage,Navigation,Scheduling,Settings,XmlRpc,Orchard.Users,Orchard.Roles,TinyMce,Orchard.Modules,Orchard.Themes,Orchard.MultiTenancy,Orchard.Pages,Orchard.Blogs,Orchard.Comments,Futures.Widgets,Orchard.Media,Orchard.Tags,Orchard.DevTools
add profiling data
feature disable Orchard.DevTools

View File

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

View File

@@ -15,6 +15,7 @@ using Orchard.Environment.Configuration;
using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Folders;
using Orchard.Environment.Extensions.Models;
using Orchard.Environment.FileSystems;
using Orchard.Environment.ShellBuilders;
using Orchard.Environment.Topology;
using Orchard.Environment.Topology.Models;

View File

@@ -49,7 +49,7 @@ namespace Orchard.Tests.Environment.Extensions {
[Test]
public void NamesFromFoldersWithModuleTxtShouldBeListed() {
var folders = new ModuleFolders(new[] { _tempFolderName });
var folders = new ModuleFolders(new[] { _tempFolderName },null,null);
var names = folders.ListNames();
Assert.That(names.Count(), Is.EqualTo(2));
Assert.That(names, Has.Some.EqualTo("Sample1"));
@@ -58,7 +58,7 @@ namespace Orchard.Tests.Environment.Extensions {
[Test]
public void ModuleTxtShouldBeParsedAndReturnedAsYamlDocument() {
var folders = new ModuleFolders(new[] { _tempFolderName });
var folders = new ModuleFolders(new[] { _tempFolderName },null,null);
var sample1 = folders.ParseManifest("Sample1");
var mapping = (Mapping)sample1.YamlDocument.Root;
var entities = mapping.Entities

View File

@@ -51,6 +51,10 @@ namespace Orchard.Tests.Environment.Extensions {
}
return null;
}
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
throw new NotImplementedException();
}
}
public class StubLoaders : IExtensionLoader {

View File

@@ -4,6 +4,7 @@ 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

@@ -56,6 +56,14 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\fluentnhibernate\FluentNHibernate.dll</HintPath>
</Reference>
<Reference Include="Machine.Migrations, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5c474de7a495cff1, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\machine.migrations\Machine.Migrations.dll</HintPath>
</Reference>
<Reference Include="Machine.Migrations.NHibernate, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\machine.migrations\Machine.Migrations.NHibernate.dll</HintPath>
</Reference>
<Reference Include="Moq, Version=4.0.812.4, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\moq\Moq.dll</HintPath>

View File

@@ -73,7 +73,6 @@
<Compile Include="Models\ShowDebugLink.cs" />
<Compile Include="Models\Simple.cs" />
<Compile Include="Permissions.cs" />
<Compile Include="Profiler.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ViewModels\ContentIndexViewModel.cs" />
<Compile Include="ViewModels\ContentDetailsViewModel.cs" />

View File

@@ -1,13 +0,0 @@
using Orchard.Environment;
namespace Orchard.DevTools {
public class Profiler : IOrchardShellEvents {
public void Activated() {
HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Initialize();
}
public void Terminating() {
}
}
}

View File

@@ -8,8 +8,8 @@ using Orchard.Core.Navigation.Models;
using Orchard.Core.Settings.Models;
using Orchard.Data;
using Orchard.Environment;
using Orchard.Environment.Configuration;
using Orchard.Environment.Extensions;
using Orchard.Environment.FileSystems;
using Orchard.Environment.ShellBuilders;
using Orchard.Environment.Topology;
using Orchard.Environment.Topology.Models;

View File

@@ -57,7 +57,7 @@ namespace Orchard.Users.Controllers {
[HttpPost]
[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings",
Justification = "Needs to take same parameter type as Controller.Redirect()")]
public ActionResult LogOn(string userNameOrEmail, string password, bool rememberMe) {
public ActionResult LogOn(string userNameOrEmail, string password, bool rememberMe, string returnUrl) {
var user = ValidateLogOn(userNameOrEmail, password);
if (!ModelState.IsValid) {
return View("LogOn", new LogOnViewModel {Title = "Log On"});
@@ -65,13 +65,19 @@ namespace Orchard.Users.Controllers {
_authenticationService.SignIn(user, rememberMe);
return this.ReturnUrlRedirect();
if (string.IsNullOrEmpty(returnUrl))
return new RedirectResult("~/");
return new RedirectResult(returnUrl);
}
public ActionResult LogOff() {
public ActionResult LogOff(string returnUrl) {
_authenticationService.SignOut();
return this.ReturnUrlRedirect();
if (string.IsNullOrEmpty(returnUrl))
return new RedirectResult("~/");
return new RedirectResult(returnUrl);
}
int MinPasswordLength {

View File

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

View File

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

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Orchard.Caching.Providers;
namespace Orchard.Caching {
public class Cache<TKey, TResult> : ICache<TKey, TResult> {
@@ -9,22 +10,21 @@ namespace Orchard.Caching {
_entries = new Dictionary<TKey, CacheEntry>();
}
#region Implementation of ICache<TKey,TResult>
public TResult Get(TKey key, Func<AcquireContext, TResult> acquire) {
public TResult Get(TKey key, Func<AcquireContext<TKey>, TResult> acquire) {
CacheEntry entry;
if (!_entries.TryGetValue(key, out entry)) {
AcquireContext context = new AcquireContext();
entry = new CacheEntry {Result = acquire(context)};
entry = new CacheEntry { VolatileItems = new List<IVolatileSignal>() };
var context = new AcquireContext<TKey>(key, volatileItem => entry.VolatileItems.Add(volatileItem));
entry.Result = acquire(context);
_entries.Add(key, entry);
}
return entry.Result;
}
#endregion
public class CacheEntry {
private class CacheEntry {
public TResult Result { get; set; }
public IList<IVolatileSignal> VolatileItems { get; set; }
}
}

View File

@@ -12,7 +12,7 @@ namespace Orchard.Caching {
#region Implementation of ICacheManager
public TResult Get<TKey, TResult>(TKey key, Func<AcquireContext, TResult> acquire) {
public TResult Get<TKey, TResult>(TKey key, Func<AcquireContext<TKey>, TResult> acquire) {
return GetCache<TKey, TResult>().Get(key, acquire);
}

View File

@@ -2,6 +2,6 @@
namespace Orchard.Caching {
public interface ICache<TKey, TResult> {
TResult Get(TKey key, Func<AcquireContext, TResult> acquire);
TResult Get(TKey key, Func<AcquireContext<TKey>, TResult> acquire);
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,6 +3,7 @@ using System.IO;
using NHibernate;
using Orchard.Data.Builders;
using Orchard.Environment.Configuration;
using Orchard.Environment.FileSystems;
using Orchard.Environment.Topology;
using Orchard.Environment.Topology.Models;
using Orchard.Logging;

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Yaml.Serialization;
using Orchard.Environment.FileSystems;
using Orchard.Localization;
namespace Orchard.Environment.Configuration {

View File

@@ -34,13 +34,7 @@ namespace Orchard.Environment.Extensions {
// This method does not load extension types, simply parses extension manifests from
// the filesystem.
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
var availableExtensions = new List<ExtensionDescriptor>();
foreach (var folder in _folders) {
foreach (var name in folder.ListNames()) {
availableExtensions.Add(GetDescriptorForExtension(name, folder));
}
}
return availableExtensions;
return _folders.SelectMany(folder=>folder.AvailableExtensions());
}
public IEnumerable<Feature> LoadFeatures(IEnumerable<FeatureDescriptor> featureDescriptors) {
@@ -57,65 +51,6 @@ namespace Orchard.Environment.Extensions {
return _activeExtensions;
}
private static ExtensionDescriptor GetDescriptorForExtension(string name, IExtensionFolders folder) {
string extensionType = folder is ThemeFolders ? "Theme" : "Module";
var parseResult = folder.ParseManifest(name);
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,
ExtensionType = extensionType,
DisplayName = GetValue(fields, "name") ?? name,
Description = GetValue(fields, "description"),
Version = GetValue(fields, "version"),
OrchardVersion = GetValue(fields, "orchardversion"),
Author = GetValue(fields, "author"),
WebSite = GetValue(fields, "website"),
Tags = GetValue(fields, "tags"),
AntiForgery = GetValue(fields, "antiforgery"),
};
extensionDescriptor.Features = GetFeaturesForExtension(GetMapping(fields, "features"), extensionDescriptor);
return extensionDescriptor;
}
private static IEnumerable<FeatureDescriptor> GetFeaturesForExtension(Mapping features, ExtensionDescriptor extensionDescriptor) {
List<FeatureDescriptor> featureDescriptors = new List<FeatureDescriptor>();
if (features != null) {
foreach (var entity in features.Entities) {
FeatureDescriptor featureDescriptor = new FeatureDescriptor {
Extension = extensionDescriptor,
Name = entity.Key.ToString(),
};
Mapping featureMapping = (Mapping)entity.Value;
foreach (var featureEntity in featureMapping.Entities) {
if (String.Equals(featureEntity.Key.ToString(), "description", StringComparison.OrdinalIgnoreCase)) {
featureDescriptor.Description = featureEntity.Value.ToString();
}
else if (String.Equals(featureEntity.Key.ToString(), "category", StringComparison.OrdinalIgnoreCase)) {
featureDescriptor.Category = featureEntity.Value.ToString();
}
else if (String.Equals(featureEntity.Key.ToString(), "dependencies", StringComparison.OrdinalIgnoreCase)) {
featureDescriptor.Dependencies = ParseFeatureDependenciesEntry(featureEntity.Value.ToString());
}
}
featureDescriptors.Add(featureDescriptor);
}
}
if (!featureDescriptors.Any(fd => fd.Name == extensionDescriptor.Name)) {
featureDescriptors.Add(new FeatureDescriptor {
Name = extensionDescriptor.Name,
Dependencies = new string[0],
Extension = extensionDescriptor,
});
}
return featureDescriptors;
}
private Feature LoadFeature(FeatureDescriptor featureDescriptor) {
var featureName = featureDescriptor.Name;
string extensionName = GetExtensionForFeature(featureName);
@@ -237,28 +172,5 @@ namespace Orchard.Environment.Extensions {
return null;
}
private static string[] ParseFeatureDependenciesEntry(string dependenciesEntry) {
List<string> dependencies = new List<string>();
foreach (var s in dependenciesEntry.Split(',')) {
dependencies.Add(s.Trim());
}
return dependencies.ToArray();
}
private static Mapping GetMapping(
IDictionary<string, DataItem> fields,
string key) {
DataItem value;
return fields.TryGetValue(key, out value) ? (Mapping)value : null;
}
private static string GetValue(
IDictionary<string, DataItem> fields,
string key) {
DataItem value;
return fields.TryGetValue(key, out value) ? value.ToString() : null;
}
}
}

View File

@@ -1,9 +1,11 @@
using System.Collections.Generic;
using Orchard.Caching;
using Orchard.Environment.FileSystems;
namespace Orchard.Environment.Extensions.Folders {
public class AreaFolders : ExtensionFolders {
public AreaFolders(IEnumerable<string> paths) :
base(paths, "Module.txt", true/*isManifestOptional*/) {
public AreaFolders(IEnumerable<string> paths, ICacheManager cacheManager, IVirtualPathProvider virtualPathProvider) :
base(paths, "Module.txt", true/*isManifestOptional*/, cacheManager, virtualPathProvider) {
}
}
}

View File

@@ -1,19 +1,67 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web.Hosting;
using Orchard.Caching;
using Orchard.Environment.Extensions.Helpers;
using Orchard.Environment.Extensions.Models;
using Orchard.Environment.FileSystems;
using Yaml.Grammar;
namespace Orchard.Environment.Extensions.Folders {
public class ParseResult {
public string Location { get; set; }
public string Name { get; set; }
public YamlDocument YamlDocument { get; set; }
}
public class ExtensionFolders : IExtensionFolders {
private readonly IEnumerable<string> _paths;
private readonly string _manifestName;
private readonly string _extensionType;
private readonly bool _manifestIsOptional;
private readonly ICacheManager _cacheManager;
private readonly IVirtualPathProvider _virtualPathProvider;
public ExtensionFolders(IEnumerable<string> paths, string manifestName, bool manifestIsOptional) {
public ExtensionFolders(
IEnumerable<string> paths,
string manifestName,
bool manifestIsOptional,
ICacheManager cacheManager,
IVirtualPathProvider virtualPathProvider) {
_paths = paths;
_manifestName = manifestName;
_extensionType = manifestName == "Theme.txt" ? "Theme" : "Module";
_manifestIsOptional = manifestIsOptional;
_cacheManager = cacheManager;
_virtualPathProvider = virtualPathProvider;
}
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));
}
return list;
}
ExtensionDescriptor GetExtensionDescriptor(string virtualPath) {
return _cacheManager.Get(virtualPath, context => {
context.IsInvalid(_virtualPathProvider.WhenPathChanges(virtualPath));
var text = _virtualPathProvider.ReadAllText(virtualPath);
var parseResult = ParseManifest(text);
return GetDescriptorForExtension(parseResult.Name, parseResult);
});
}
public IEnumerable<string> ListNames() {
@@ -43,10 +91,10 @@ namespace Orchard.Environment.Extensions.Folders {
if (File.Exists(extensionManifestPath)) {
var yamlStream = YamlParser.Load(extensionManifestPath);
return new ParseResult {
Location = path,
Name = name,
YamlDocument = yamlStream.Documents.Single()
};
Location = path,
Name = name,
YamlDocument = yamlStream.Documents.Single()
};
}
if (_manifestIsOptional) {
@@ -55,13 +103,94 @@ namespace Orchard.Environment.Extensions.Folders {
bool success;
var yamlStream = parser.ParseYamlStream(yamlInput, out success);
return new ParseResult {
Location = path,
Name = name,
YamlDocument = yamlStream.Documents.Single()
};
Location = path,
Name = name,
YamlDocument = yamlStream.Documents.Single()
};
}
}
return null;
}
private ExtensionDescriptor GetDescriptorForExtension(string name, 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,
ExtensionType = _extensionType,
DisplayName = GetValue(fields, "name") ?? name,
Description = GetValue(fields, "description"),
Version = GetValue(fields, "version"),
OrchardVersion = GetValue(fields, "orchardversion"),
Author = GetValue(fields, "author"),
WebSite = GetValue(fields, "website"),
Tags = GetValue(fields, "tags"),
AntiForgery = GetValue(fields, "antiforgery"),
};
extensionDescriptor.Features = GetFeaturesForExtension(GetMapping(fields, "features"), extensionDescriptor);
return extensionDescriptor;
}
private static IEnumerable<FeatureDescriptor> GetFeaturesForExtension(Mapping features, ExtensionDescriptor extensionDescriptor) {
List<FeatureDescriptor> featureDescriptors = new List<FeatureDescriptor>();
if (features != null) {
foreach (var entity in features.Entities) {
FeatureDescriptor featureDescriptor = new FeatureDescriptor {
Extension = extensionDescriptor,
Name = entity.Key.ToString(),
};
Mapping featureMapping = (Mapping)entity.Value;
foreach (var featureEntity in featureMapping.Entities) {
if (String.Equals(featureEntity.Key.ToString(), "description", StringComparison.OrdinalIgnoreCase)) {
featureDescriptor.Description = featureEntity.Value.ToString();
}
else if (String.Equals(featureEntity.Key.ToString(), "category", StringComparison.OrdinalIgnoreCase)) {
featureDescriptor.Category = featureEntity.Value.ToString();
}
else if (String.Equals(featureEntity.Key.ToString(), "dependencies", StringComparison.OrdinalIgnoreCase)) {
featureDescriptor.Dependencies = ParseFeatureDependenciesEntry(featureEntity.Value.ToString());
}
}
featureDescriptors.Add(featureDescriptor);
}
}
if (!featureDescriptors.Any(fd => fd.Name == extensionDescriptor.Name)) {
featureDescriptors.Add(new FeatureDescriptor {
Name = extensionDescriptor.Name,
Dependencies = new string[0],
Extension = extensionDescriptor,
});
}
return featureDescriptors;
}
private static string[] ParseFeatureDependenciesEntry(string dependenciesEntry) {
List<string> dependencies = new List<string>();
foreach (var s in dependenciesEntry.Split(',')) {
dependencies.Add(s.Trim());
}
return dependencies.ToArray();
}
private static Mapping GetMapping(
IDictionary<string, DataItem> fields,
string key) {
DataItem value;
return fields.TryGetValue(key, out value) ? (Mapping)value : null;
}
private static string GetValue(
IDictionary<string, DataItem> fields,
string key) {
DataItem value;
return fields.TryGetValue(key, out value) ? value.ToString() : null;
}
}
}

View File

@@ -1,15 +1,11 @@
using System.Collections.Generic;
using Orchard.Environment.Extensions.Models;
using Yaml.Grammar;
namespace Orchard.Environment.Extensions.Folders {
public interface IExtensionFolders {
IEnumerable<string> ListNames();
ParseResult ParseManifest(string name);
IEnumerable<ExtensionDescriptor> AvailableExtensions();
}
public class ParseResult {
public string Location { get; set; }
public string Name { get; set; }
public YamlDocument YamlDocument { get; set; }
}
}

View File

@@ -1,9 +1,11 @@
using System.Collections.Generic;
using Orchard.Caching;
using Orchard.Environment.FileSystems;
namespace Orchard.Environment.Extensions.Folders {
public class ModuleFolders : ExtensionFolders {
public ModuleFolders(IEnumerable<string> paths) :
base(paths, "Module.txt", false/*isManifestOptional*/) {
public ModuleFolders(IEnumerable<string> paths, ICacheManager cacheManager, IVirtualPathProvider virtualPathProvider) :
base(paths, "Module.txt", false/*isManifestOptional*/, cacheManager, virtualPathProvider) {
}
}
}

View File

@@ -1,9 +1,11 @@
using System.Collections.Generic;
using Orchard.Caching;
using Orchard.Environment.FileSystems;
namespace Orchard.Environment.Extensions.Folders {
public class ThemeFolders : ExtensionFolders {
public ThemeFolders(IEnumerable<string> paths) :
base(paths, "Theme.txt", false/*manifestIsOptional*/) {
public ThemeFolders(IEnumerable<string> paths, ICacheManager cacheManager, IVirtualPathProvider virtualPathProvider) :
base(paths, "Theme.txt", false/*manifestIsOptional*/, cacheManager, virtualPathProvider) {
}
}
}

View File

@@ -3,33 +3,9 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web.Hosting;
using Orchard.Environment.FileSystems;
namespace Orchard.Environment.Configuration {
/// <summary>
/// Abstraction of App_Data folder
/// Expected to work on physical filesystem, but decouples core
/// system from web hosting apis
/// </summary>
public interface IAppDataFolder {
IEnumerable<string> ListFiles(string path);
IEnumerable<string> ListDirectories(string path);
void CreateFile(string path, string content);
string ReadFile(string path);
void DeleteFile(string path);
bool FileExists(string path);
string CreateDirectory(string path);
/// <summary>
/// May be called to initialize component when not in a hosting environment
/// app domain
/// </summary>
void SetBasePath(string basePath);
string MapPath(string path);
}
public class AppDataFolder : IAppDataFolder {
protected string _basePath;

View File

@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Web.Hosting;
using Orchard.Caching.Providers;
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");
public DefaultVirtualPathProvider(IClock clock) {
_clock = clock;
}
public string ReadAllText(string virtualPath) {
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);
}
class VirtualPathSignal : IVolatileSignal {
private readonly string _virtualPath;
public VirtualPathSignal(DefaultVirtualPathProvider provider, string virtualPath) {
_virtualPath = virtualPath;
Provider = provider;
}
public IVolatileProvider Provider { get; set; }
}
public void Enlist(IVolatileSink sink) {
_sinks.Add(sink);
}
}
}

View File

@@ -0,0 +1,28 @@
using System.Collections.Generic;
namespace Orchard.Environment.FileSystems {
/// <summary>
/// Abstraction of App_Data folder
/// Expected to work on physical filesystem, but decouples core
/// system from web hosting apis
/// </summary>
public interface IAppDataFolder {
IEnumerable<string> ListFiles(string path);
IEnumerable<string> ListDirectories(string path);
void CreateFile(string path, string content);
string ReadFile(string path);
void DeleteFile(string path);
bool FileExists(string path);
string CreateDirectory(string path);
/// <summary>
/// May be called to initialize component when not in a hosting environment
/// app domain
/// </summary>
void SetBasePath(string basePath);
string MapPath(string path);
}
}

View File

@@ -0,0 +1,9 @@
using Orchard.Caching.Providers;
namespace Orchard.Environment.FileSystems {
public interface IVirtualPathProvider : IVolatileProvider {
IVolatileSignal WhenPathChanges(string path);
string ReadAllText(string virtualPath);
}
}

View File

@@ -10,6 +10,7 @@ using Orchard.Environment.Configuration;
using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Folders;
using Orchard.Environment.Extensions.Loaders;
using Orchard.Environment.FileSystems;
using Orchard.Environment.ShellBuilders;
using Orchard.Environment.Topology;
using Orchard.Events;

View File

@@ -106,7 +106,8 @@ namespace Orchard.Environment.ShellBuilders {
private IRegistrationBuilder<object, ConcreteReflectionActivatorData, SingleRegistrationStyle> RegisterType(ContainerBuilder builder, ShellTopologyItem item) {
return builder.RegisterType(item.Type)
.WithProperty("Feature", item.Feature);
.WithProperty("Feature", item.Feature)
.WithMetadata("Feature", item.Feature);
}
}
}

View File

@@ -2,7 +2,7 @@
using System.IO;
using System.Runtime.Serialization;
using System.Xml;
using Orchard.Environment.Configuration;
using Orchard.Environment.FileSystems;
using Orchard.Environment.Topology.Models;
using Orchard.Localization;
using Orchard.Logging;

View File

@@ -1,17 +0,0 @@
using System;
using System.Web.Mvc;
namespace Orchard.Mvc.Extensions {
public static class ControllerExtensions {
public static RedirectResult ReturnUrlRedirect(this Controller controller) {
string returnUrl = controller.Request.QueryString["ReturnUrl"];
// prevents phishing attacks by using only relative urls
if(!returnUrl.StartsWith("/")) {
return new RedirectResult("~/");
}
return new RedirectResult(returnUrl);
}
}
}

View File

@@ -63,6 +63,18 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\sharpziplib\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
<Reference Include="Machine.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5c474de7a495cff1, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\machine.migrations\Machine.Core.dll</HintPath>
</Reference>
<Reference Include="Machine.Migrations, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5c474de7a495cff1, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\machine.migrations\Machine.Migrations.dll</HintPath>
</Reference>
<Reference Include="Machine.Migrations.NHibernate, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\machine.migrations\Machine.Migrations.NHibernate.dll</HintPath>
</Reference>
<Reference Include="NHibernate, Version=2.1.0.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\fluentnhibernate\NHibernate.dll</HintPath>
@@ -134,8 +146,14 @@
<Compile Include="Caching\AcquireContext.cs" />
<Compile Include="Caching\Cache.cs" />
<Compile Include="Caching\DefaultCacheManager.cs" />
<Compile Include="Caching\Providers\IVolatileSink.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="Commands\CommandParameters.cs" />
<Compile Include="Commands\CommandDescriptor.cs" />
<Compile Include="Commands\CommandHandlerDescriptor.cs" />
@@ -173,7 +191,7 @@
<Compile Include="Environment\AutofacUtil\DynamicProxy2\DynamicProxyContext.cs" />
<Compile Include="Environment\AutofacUtil\DynamicProxy2\DynamicProxyExtensions.cs" />
<Compile Include="Environment\AutofacUtil\DynamicProxy2\ConstructorFinderWrapper.cs" />
<Compile Include="Environment\Configuration\AppDataFolder.cs" />
<Compile Include="Environment\FileSystems\AppDataFolder.cs" />
<Compile Include="Environment\Configuration\ShellSettingsManager.cs" />
<Compile Include="Environment\AutofacUtil\ContainerUpdater.cs" />
<Compile Include="Environment\ShellBuilders\ShellContextFactory.cs" />
@@ -204,7 +222,6 @@
<Compile Include="Modules\IModuleFeature.cs" />
<Compile Include="Modules\IModuleService.cs" />
<Compile Include="Mvc\AntiForgery\ValidateAntiForgeryTokenOrchardAttribute.cs" />
<Compile Include="Mvc\Extensions\ControllerExtensions.cs" />
<Compile Include="Mvc\Extensions\ModelStateDictionaryExtensions.cs" />
<Compile Include="Mvc\Html\FileRegistrationContextExtensions.cs" />
<Compile Include="Mvc\Extensions\UrlHelperExtensions.cs" />