Merge branch '1.9-int' into 1.x

This commit is contained in:
Sipke Schoorstra
2015-04-16 16:10:57 +02:00
28 changed files with 346 additions and 199 deletions

View File

@@ -111,7 +111,9 @@
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="false"/>
<modules runAllManagedModulesForAllRequests="false">
<remove name="OutputCache"/>
</modules>
<handlers accessPolicy="Script">
<!-- Clear all handlers, prevents executing code file extensions or returning any file contents. -->
<clear/>

View File

@@ -273,7 +273,11 @@ namespace Orchard.Tests.Modules.DesignerTools.Services
new JProperty("value", "null")),
new JObject(
new JProperty("name", "TypePartDefinition"),
new JProperty("value", "ContentTypePartDefinition")),
new JProperty("value", "ContentTypePartDefinition"),
new JProperty("children", new JArray(
new JObject(
new JProperty("name", "ContentTypeDefinition"),
new JProperty("value", "null"))))),
new JObject(
new JProperty("name", "PartDefinition"),
new JProperty("value", "ContentPartDefinition"),
@@ -349,7 +353,10 @@ namespace Orchard.Tests.Modules.DesignerTools.Services
new JProperty("value", "SettingsDictionary"))))),
new JObject(
new JProperty("name", "Settings"),
new JProperty("value", "SettingsDictionary"))))),
new JProperty("value", "SettingsDictionary")),
new JObject(
new JProperty("name", "ContentTypeDefinition"),
new JProperty("value", "null"))))),
new JObject(
new JProperty("name", "PartDefinition"),
new JProperty("value", "ContentPartDefinition"),

View File

@@ -1,4 +1,5 @@
using Autofac;
using System;
using Autofac;
using NUnit.Framework;
using Orchard.Environment.Configuration;
using Orchard.Mvc;
@@ -17,7 +18,7 @@ namespace Orchard.Tests.Modules.Widgets.RuleEngine {
[SetUp]
public void Init() {
var builder = new ContainerBuilder();
_shellSettings = new ShellSettings {RequestUrlPrefix = string.Empty};
_shellSettings = new ShellSettings { RequestUrlPrefix = String.Empty };
builder.RegisterType<UrlRuleProvider>().As<IRuleProvider>();
builder.RegisterInstance(_shellSettings);
_stubContextAccessor = new StubHttpContextAccessor();
@@ -28,15 +29,15 @@ namespace Orchard.Tests.Modules.Widgets.RuleEngine {
[Test]
public void UrlForHomePageMatchesHomePagePath() {
_stubContextAccessor.StubContext = new StubHttpContext("~/");
var context = new RuleContext {FunctionName = "url", Arguments = new[] {"~/"}};
_stubContextAccessor.Set(new StubHttpContext("~/"));
var context = new RuleContext { FunctionName = "url", Arguments = new[] { "~/" } };
_urlRuleProvider.Process(context);
Assert.That(context.Result, Is.True);
}
[Test]
public void UrlForAboutPageMatchesAboutPagePath() {
_stubContextAccessor.StubContext = new StubHttpContext("~/about");
_stubContextAccessor.Set(new StubHttpContext("~/about"));
var context = new RuleContext { FunctionName = "url", Arguments = new[] { "~/about" } };
_urlRuleProvider.Process(context);
Assert.That(context.Result, Is.True);
@@ -44,7 +45,7 @@ namespace Orchard.Tests.Modules.Widgets.RuleEngine {
[Test]
public void UrlForBlogWithEndingWildcardMatchesBlogPostPageInSaidBlog() {
_stubContextAccessor.StubContext = new StubHttpContext("~/my-blog/my-blog-post");
_stubContextAccessor.Set(new StubHttpContext("~/my-blog/my-blog-post"));
var context = new RuleContext { FunctionName = "url", Arguments = new[] { "~/my-blog/*" } };
_urlRuleProvider.Process(context);
Assert.That(context.Result, Is.True);
@@ -52,7 +53,7 @@ namespace Orchard.Tests.Modules.Widgets.RuleEngine {
[Test]
public void UrlForHomePageDoesNotMatchAboutPagePath() {
_stubContextAccessor.StubContext = new StubHttpContext("~/about");
_stubContextAccessor.Set(new StubHttpContext("~/about"));
var context = new RuleContext { FunctionName = "url", Arguments = new[] { "~/" } };
_urlRuleProvider.Process(context);
Assert.That(context.Result, Is.False);
@@ -60,7 +61,7 @@ namespace Orchard.Tests.Modules.Widgets.RuleEngine {
[Test]
public void UrlForAboutPageMatchesDifferentCasedAboutPagePath() {
_stubContextAccessor.StubContext = new StubHttpContext("~/About");
_stubContextAccessor.Set(new StubHttpContext("~/About"));
var context = new RuleContext { FunctionName = "url", Arguments = new[] { "~/about" } };
_urlRuleProvider.Process(context);
Assert.That(context.Result, Is.True);
@@ -68,7 +69,7 @@ namespace Orchard.Tests.Modules.Widgets.RuleEngine {
[Test]
public void UrlForAboutPageWithEndingSlashMatchesAboutPagePath() {
_stubContextAccessor.StubContext = new StubHttpContext("~/About/");
_stubContextAccessor.Set(new StubHttpContext("~/About/"));
var context = new RuleContext { FunctionName = "url", Arguments = new[] { "~/about" } };
_urlRuleProvider.Process(context);
Assert.That(context.Result, Is.True);
@@ -76,7 +77,7 @@ namespace Orchard.Tests.Modules.Widgets.RuleEngine {
[Test]
public void UrlForHomePageMatchesHomePagePathWithUrlPrefix() {
_stubContextAccessor.StubContext = new StubHttpContext("~/site1");
_stubContextAccessor.Set(new StubHttpContext("~/site1"));
_shellSettings.RequestUrlPrefix = "site1";
var context = new RuleContext { FunctionName = "url", Arguments = new[] { "~/" } };
_urlRuleProvider.Process(context);

View File

@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Web;
using Autofac;
using Moq;
using NHibernate;
@@ -17,7 +16,6 @@ using Orchard.DisplayManagement.Implementation;
using Orchard.Environment;
using Orchard.Localization.Records;
using Orchard.Localization.Services;
using Orchard.Mvc;
using Orchard.Security;
using Orchard.Tests.ContentManagement;
using Orchard.Tests.Stubs;
@@ -31,10 +29,11 @@ namespace Orchard.Tests.Localization {
private ISessionFactory _sessionFactory;
private ISession _session;
private string _databaseFileName;
private StubWorkContext _stubWorkContext;
[TestFixtureSetUp]
public void InitFixture() {
_databaseFileName = System.IO.Path.GetTempFileName();
_databaseFileName = Path.GetTempFileName();
_sessionFactory = DataUtility.CreateSessionFactory(
_databaseFileName,
typeof(CultureRecord));
@@ -43,6 +42,7 @@ namespace Orchard.Tests.Localization {
[SetUp]
public void Init() {
var builder = new ContainerBuilder();
_stubWorkContext = new StubWorkContext();
builder.RegisterType<DefaultShapeTableManager>().As<IShapeTableManager>();
builder.RegisterType<DefaultShapeFactory>().As<IShapeFactory>();
builder.RegisterInstance(new Mock<IContentDefinitionManager>().Object);
@@ -50,12 +50,11 @@ namespace Orchard.Tests.Localization {
builder.RegisterInstance(new Mock<IAuthorizer>().Object);
builder.RegisterInstance(new Mock<INotifier>().Object);
builder.RegisterInstance(new Mock<IContentDisplay>().Object);
builder.RegisterType<StubHttpContextAccessor>().As<IHttpContextAccessor>();
builder.RegisterType<WorkContextAccessor>().As<IWorkContextAccessor>();
builder.RegisterInstance(_stubWorkContext);
builder.RegisterInstance(new StubWorkContextAccessor(_stubWorkContext)).As<IWorkContextAccessor>();
builder.RegisterType<DefaultContentManager>().As<IContentManager>();
builder.RegisterType<DefaultContentManagerSession>().As<IContentManagerSession>();
builder.RegisterType<OrchardServices>().As<IOrchardServices>();
builder.RegisterType<TestCultureSelector>().As<ICultureSelector>();
builder.RegisterType<DefaultCultureManager>().As<ICultureManager>();
builder.RegisterType<Signals>().As<ISignals>();
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
@@ -106,15 +105,9 @@ namespace Orchard.Tests.Localization {
}
[Test]
public void CultureManagerReturnsCultureFromSelector() {
Assert.That(_cultureManager.GetCurrentCulture(null), Is.EqualTo("en-US"));
public void CultureManagerReturnsCultureFromWorkContext() {
_stubWorkContext.CultureName = "nl-NL";
Assert.That(_cultureManager.GetCurrentCulture(null), Is.EqualTo("nl-NL"));
}
}
public class TestCultureSelector : ICultureSelector {
public CultureSelectorResult GetCulture(HttpContextBase context) {
return new CultureSelectorResult { Priority = 1, CultureName = "en-US" };
}
}
}
}

View File

@@ -0,0 +1,34 @@
using Autofac;
using NUnit.Framework;
using Orchard.Localization.Services;
using Orchard.Mvc;
using Orchard.Tests.Stubs;
namespace Orchard.Tests.Localization {
[TestFixture]
public class CurrentCultureWorkContextTests {
private IContainer _container;
private IWorkContextStateProvider _currentCultureStateProvider;
private WorkContext _workContext;
[SetUp]
public void Init() {
var builder = new ContainerBuilder();
_workContext = new StubWorkContext();
builder.RegisterInstance(new StubCultureSelector("or-CH")).As<ICultureSelector>();
builder.RegisterInstance(new StubHttpContext("~/"));
builder.RegisterInstance(_workContext);
builder.RegisterType<StubHttpContextAccessor>().As<IHttpContextAccessor>();
builder.RegisterType<CurrentCultureWorkContext>().As<IWorkContextStateProvider>();
_container = builder.Build();
_currentCultureStateProvider = _container.Resolve<IWorkContextStateProvider>();
}
[Test]
public void CultureManagerReturnsCultureFromSelectors() {
var actualCulture = _currentCultureStateProvider.Get<string>("CurrentCulture")(_workContext);
var expectedCulture = "or-CH";
Assert.That(actualCulture, Is.EqualTo(expectedCulture));
}
}
}

View File

@@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Autofac;
using Moq;
using Orchard.Localization.Services;
@@ -28,16 +25,19 @@ namespace Orchard.Tests.Localization {
internal class StubWorkContext : WorkContext {
private string _cultureName;
private string _calendarName;
private TimeZoneInfo _timeZone;
public StubWorkContext() {
}
public StubWorkContext(string cultureName, string calendarName, TimeZoneInfo timeZone) {
_cultureName = cultureName;
_calendarName = calendarName;
_timeZone = timeZone;
CultureName = cultureName;
CalendarName = calendarName;
TimeZone = timeZone;
}
public string CultureName { get; set; }
public string CalendarName { get; set; }
public TimeZoneInfo TimeZone { get; set; }
public override T Resolve<T>() {
throw new NotImplementedException();
}
@@ -47,9 +47,9 @@ namespace Orchard.Tests.Localization {
}
public override T GetState<T>(string name) {
if (name == "CurrentCulture") return (T)((object)_cultureName);
if (name == "CurrentCalendar") return (T)((object)_calendarName);
if (name == "CurrentTimeZone") return (T)((object)_timeZone);
if (name == "CurrentCulture") return (T)((object)CultureName);
if (name == "CurrentCalendar") return (T)((object)CalendarName);
if (name == "CurrentTimeZone") return (T)((object)TimeZone);
throw new NotImplementedException(String.Format("Property '{0}' is not implemented.", name));
}
@@ -60,17 +60,17 @@ namespace Orchard.Tests.Localization {
internal class StubWorkContextAccessor : IWorkContextAccessor {
private WorkContext _workContext;
private readonly WorkContext _workContext;
public StubWorkContextAccessor(WorkContext workContext) {
_workContext = workContext;
}
public WorkContext GetContext(System.Web.HttpContextBase httpContext) {
public WorkContext GetContext(HttpContextBase httpContext) {
throw new NotImplementedException();
}
public IWorkContextScope CreateWorkContextScope(System.Web.HttpContextBase httpContext) {
public IWorkContextScope CreateWorkContextScope(HttpContextBase httpContext) {
throw new NotImplementedException();
}

View File

@@ -259,10 +259,12 @@
<Compile Include="FileSystems\Dependencies\AssemblyProbingFolderTests.cs" />
<Compile Include="FileSystems\Dependencies\DependenciesFolderTests.cs" />
<Compile Include="FileSystems\VirtualPath\DefaultVirtualPathProviderTests.cs" />
<Compile Include="Localization\CurrentCultureWorkContextTests.cs" />
<Compile Include="Localization\CultureManagerTests.cs" />
<Compile Include="Localization\DateTimePartsTests.cs" />
<Compile Include="Localization\DefaultDateLocalizationServicesTests.cs" />
<Compile Include="Localization\DefaultDateFormatterTests.cs" />
<Compile Include="Stubs\StubCultureSelector.cs" />
<Compile Include="Localization\TestHelpers.cs" />
<Compile Include="Logging\OrchardFileAppenderTests.cs" />
<Compile Include="Messaging\MessagingChannelStub.cs" />

View File

@@ -0,0 +1,16 @@
using System.Web;
using Orchard.Localization.Services;
namespace Orchard.Tests.Stubs {
public class StubCultureSelector : ICultureSelector {
private readonly string _cultureName;
public StubCultureSelector(string cultureName) {
_cultureName = cultureName;
}
public CultureSelectorResult GetCulture(HttpContextBase context) {
return new CultureSelectorResult { Priority = 1, CultureName = _cultureName };
}
}
}

View File

@@ -5,16 +5,19 @@ namespace Orchard.Tests.Stubs {
public class StubHttpContextAccessor : IHttpContextAccessor {
private HttpContextBase _httpContext;
public HttpContextBase StubContext {
set { _httpContext = value; }
public StubHttpContextAccessor() {
}
public StubHttpContextAccessor(HttpContextBase httpContext) {
_httpContext = httpContext;
}
public HttpContextBase Current() {
return _httpContext;
}
public void Set(HttpContextBase stub) {
_httpContext = stub;
public void Set(HttpContextBase httpContext) {
_httpContext = httpContext;
}
}
}

View File

@@ -1,34 +1,10 @@
var LayoutEditor;
(function ($, LayoutEditor) {
var decode = function(value) {
var decode = function (value) {
return !!value ? decodeURIComponent(value.replace(/\+/g, "%20")) : null;
};
var decodeGraph = function (graph) {
if (!!graph.html) {
graph.html = decode(graph.html);
}
if (!!graph.data) {
var items = $.deserialize(graph.data);
for (var i = 0; i < items.length; i++) {
items[i] = decode(items[i]);
}
graph.data = $.param(items);
}
if (!!graph.children) {
for (var i = 0; i < graph.children.length; i++) {
decodeGraph(graph.children[i]);
}
}
};
LayoutEditor.decode = decode;
LayoutEditor.decodeLayoutGraph = decodeGraph;
})(jQuery, LayoutEditor || (LayoutEditor = {}));

View File

@@ -13,14 +13,14 @@ namespace Orchard.Layouts.Services {
// Consider combining this class with DefaultContentDisplay to reuse shared code, for example by inheriting from a common base class.
public abstract class ContentDisplayBase : Component {
private readonly IShapeFactory _shapeFactory;
private readonly Lazy<IShapeTableLocator> _shapeTableLocator;
private readonly Lazy<IShapeTableLocator> _shapeTableLocator;
private readonly RequestContext _requestContext;
private readonly IVirtualPathProvider _virtualPathProvider;
private readonly IWorkContextAccessor _workContextAccessor;
protected ContentDisplayBase(
IShapeFactory shapeFactory,
Lazy<IShapeTableLocator> shapeTableLocator,
Lazy<IShapeTableLocator> shapeTableLocator,
RequestContext requestContext,
IVirtualPathProvider virtualPathProvider,
IWorkContextAccessor workContextAccessor) {
@@ -109,9 +109,9 @@ namespace Orchard.Layouts.Services {
private void BindPlacement(BuildShapeContext context, string displayType, string stereotype) {
context.FindPlacement = (partShapeType, differentiator, defaultLocation) => {
var workContext = _workContextAccessor.GetContext(_requestContext.HttpContext);
var theme = workContext.CurrentTheme;
var shapeTable = _shapeTableLocator.Value.Lookup(theme.Id);
var request = _requestContext.HttpContext.Request;
var shapeTable = workContext.HttpContext != null
? _shapeTableLocator.Value.Lookup(workContext.CurrentTheme.Id)
: _shapeTableLocator.Value.Lookup(null);
ShapeDescriptor descriptor;
if (shapeTable.Descriptors.TryGetValue(partShapeType, out descriptor)) {

View File

@@ -43,10 +43,9 @@
}
});
(function() {
var editorConfig = @Html.Raw(Model.ConfigurationData);
var editorCanvasData = @Html.Raw(Model.Data);
var editorConfig = JSON.parse(LayoutEditor.decode("@Html.Raw(Url.Encode(Model.ConfigurationData))"));
var editorCanvasData = JSON.parse(LayoutEditor.decode("@Html.Raw(Url.Encode(Model.Data))"));
LayoutEditor.decodeLayoutGraph(editorCanvasData);
window.layoutEditor = new LayoutEditor.Editor(editorConfig, editorCanvasData);
})(jQuery);
</script>

View File

@@ -43,11 +43,9 @@
html: LayoutEditor.decode("@Url.Encode(Model.ElementHtml)"),
isTemplated: false
},
elementEditorModel: @Html.Raw(Model.ElementEditorModel.ToJson())
elementEditorModel: LayoutEditor.decode("@Html.Raw(Url.Encode(Model.ElementEditorModel.ToJson()))")
};
LayoutEditor.decodeLayoutGraph(payload.element);
LayoutEditor.decodeLayoutGraph(payload.elementEditorModel);
window.parent.currentDialog.trigger("command", payload);
});
</script>

View File

@@ -16,7 +16,7 @@ namespace Contrib.Cache.Database {
.Column<int>("GraceTime", c => c.Nullable())
.Column<DateTime>("ValidUntilUtc")
.Column<DateTime>("StoredUntilUtc")
.Column<string>("Output", column => column.Unlimited())
.Column<byte[]>("Output", column => column.Unlimited().WithType(DbType.Binary))
.Column<string>("ContentType")
.Column<string>("QueryString", column => column.WithLength(2048))
.Column<string>("CacheKey", column => column.WithLength(2048))
@@ -31,7 +31,7 @@ namespace Contrib.Cache.Database {
.CreateIndex("IDX_CacheItemRecord_CacheKey", "CacheKey")
);
return 2;
return 3;
}
public int UpdateFrom1() {
@@ -45,5 +45,14 @@ namespace Contrib.Cache.Database {
return 2;
}
public int UpdateFrom2() {
SchemaBuilder.AlterTable("CacheItemRecord",
table => {
table.AlterColumn("Output", c => c.Unlimited().WithType(DbType.Binary));
});
return 3;
}
}
}

View File

@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
namespace Orchard.OutputCache.Filters {
public class CaptureStream : Stream {
public CaptureStream(Stream innerStream) {
_innerStream = innerStream;
_captureStream = new MemoryStream();
}
private readonly Stream _innerStream;
private readonly MemoryStream _captureStream;
public override bool CanRead {
get { return _innerStream.CanRead; }
}
public override bool CanSeek {
get { return _innerStream.CanSeek; }
}
public override bool CanWrite {
get { return _innerStream.CanWrite; }
}
public override long Length {
get { return _innerStream.Length; }
}
public override long Position {
get { return _innerStream.Position; }
set { _innerStream.Position = value; }
}
public override long Seek(long offset, SeekOrigin direction) {
return _innerStream.Seek(offset, direction);
}
public override void SetLength(long length) {
_innerStream.SetLength(length);
}
public override void Close() {
_innerStream.Close();
}
public override void Flush() {
if (_captureStream.Length > 0) {
OnCaptured();
_captureStream.SetLength(0);
}
_innerStream.Flush();
}
public override int Read(byte[] buffer, int offset, int count) {
return _innerStream.Read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count) {
_captureStream.Write(buffer, offset, count);
_innerStream.Write(buffer, offset, count);
}
public event Action<byte[]> Captured;
protected virtual void OnCaptured() {
Captured(_captureStream.ToArray());
}
}
}

View File

@@ -19,7 +19,6 @@ using Orchard.Mvc.Extensions;
using Orchard.Mvc.Filters;
using Orchard.OutputCache.Models;
using Orchard.OutputCache.Services;
using Orchard.OutputCache.ViewModels;
using Orchard.Services;
using Orchard.Themes;
using Orchard.UI.Admin;
@@ -78,12 +77,19 @@ namespace Orchard.OutputCache.Filters {
private string _cacheKey;
private string _invariantCacheKey;
private bool _transformRedirect;
private Func<ControllerContext, string> _completeResponseFunc;
private bool _isCachingRequest;
public void OnActionExecuting(ActionExecutingContext filterContext) {
Logger.Debug("Incoming request for URL '{0}'.", filterContext.RequestContext.HttpContext.Request.RawUrl);
// This filter is not reentrant (multiple executions within the same request are
// not supported) so child actions are ignored completely.
if (filterContext.IsChildAction) {
Logger.Debug("Action '{0}' ignored because it's a child action.", filterContext.ActionDescriptor.ActionName);
return;
}
_now = _clock.UtcNow;
_workContext = _workContextAccessor.GetContext();
_cacheKey = ComputeCacheKey(filterContext, GetCacheKeyParameters(filterContext));
@@ -167,16 +173,14 @@ namespace Orchard.OutputCache.Filters {
public void OnResultExecuted(ResultExecutedContext filterContext) {
var captureHandlerIsAttached = false;
try {
string renderedOutput = null;
if (_completeResponseFunc != null) {
renderedOutput = _completeResponseFunc(filterContext);
}
if (renderedOutput == null) {
// This filter is not reentrant (multiple executions within the same request are
// not supported) so child actions are ignored completely.
if (filterContext.IsChildAction || !_isCachingRequest)
return;
}
Logger.Debug("Item '{0}' was rendered.", _cacheKey);
@@ -203,42 +207,52 @@ namespace Orchard.OutputCache.Filters {
// Include each content item ID as tags for the cache entry.
var contentItemIds = _displayedContentItemHandler.GetDisplayed().Select(x => x.ToString(CultureInfo.InvariantCulture)).ToArray();
// Capture the response output using a custom filter stream.
var response = filterContext.HttpContext.Response;
var cacheItem = new CacheItem() {
CachedOnUtc = _now,
Duration = cacheDuration,
GraceTime = cacheGraceTime,
Output = renderedOutput,
ContentType = response.ContentType,
QueryString = filterContext.HttpContext.Request.Url.Query,
CacheKey = _cacheKey,
InvariantCacheKey = _invariantCacheKey,
Url = filterContext.HttpContext.Request.Url.AbsolutePath,
Tenant = _shellSettings.Name,
StatusCode = response.StatusCode,
Tags = new[] { _invariantCacheKey }.Union(contentItemIds).ToArray()
var captureStream = new CaptureStream(response.Filter);
response.Filter = captureStream;
captureStream.Captured += (output) => {
try {
var cacheItem = new CacheItem() {
CachedOnUtc = _now,
Duration = cacheDuration,
GraceTime = cacheGraceTime,
Output = output,
ContentType = response.ContentType,
QueryString = filterContext.HttpContext.Request.Url.Query,
CacheKey = _cacheKey,
InvariantCacheKey = _invariantCacheKey,
Url = filterContext.HttpContext.Request.Url.AbsolutePath,
Tenant = _shellSettings.Name,
StatusCode = response.StatusCode,
Tags = new[] { _invariantCacheKey }.Union(contentItemIds).ToArray()
};
// Write the rendered item to the cache.
_cacheStorageProvider.Remove(_cacheKey);
_cacheStorageProvider.Set(_cacheKey, cacheItem);
Logger.Debug("Item '{0}' was written to cache.", _cacheKey);
// Also add the item tags to the tag cache.
foreach (var tag in cacheItem.Tags) {
_tagCache.Tag(tag, _cacheKey);
}
}
finally {
// Always release the cache key lock when the request ends.
ReleaseCacheKeyLock();
}
};
// Write the rendered item to the cache.
_cacheStorageProvider.Remove(_cacheKey);
_cacheStorageProvider.Set(_cacheKey, cacheItem);
Logger.Debug("Item '{0}' was written to cache.", _cacheKey);
// Also add the item tags to the tag cache.
foreach (var tag in cacheItem.Tags) {
_tagCache.Tag(tag, _cacheKey);
}
captureHandlerIsAttached = true;
}
finally {
// Always release the cache key lock when the request ends.
if (_cacheKey != null) {
object cacheKeyLock;
if (_cacheKeyLocks.TryGetValue(_cacheKey, out cacheKeyLock) && Monitor.IsEntered(cacheKeyLock)) {
Logger.Debug("Releasing cache key lock for item '{0}'.", _cacheKey);
Monitor.Exit(cacheKeyLock);
}
}
// If the response filter stream capture handler was attached then we'll trust
// it to release the cache key lock at some point in the future when the stream
// is flushed; otherwise we'll make sure we'll release it here.
if (!captureHandlerIsAttached)
ReleaseCacheKeyLock();
}
}
@@ -267,12 +281,6 @@ namespace Orchard.OutputCache.Filters {
return false;
}
// Ignore child actions, e.g. HomeController is using RenderAction()
if (filterContext.IsChildAction) {
Logger.Debug("Request for item '{0}' ignored because it's a child action.", _cacheKey);
return false;
}
// Ignore authenticated requests unless the setting to cache them is true.
if (_workContext.CurrentUser != null && !CacheSettings.CacheAuthenticatedRequests) {
Logger.Debug("Request for item '{0}' ignored because user is authenticated.", _cacheKey);
@@ -329,7 +337,7 @@ namespace Orchard.OutputCache.Filters {
// Vary by action parameters.
foreach (var p in filterContext.ActionParameters)
result.Add(p.Key, p.Value);
result.Add("PARAM:" + p.Key, p.Value);
// Vary by theme.
result.Add("theme", _themeManager.GetRequestTheme(filterContext.RequestContext).Id.ToLowerInvariant());
@@ -438,7 +446,6 @@ namespace Orchard.OutputCache.Filters {
private void ServeCachedItem(ActionExecutingContext filterContext, CacheItem cacheItem) {
var response = filterContext.HttpContext.Response;
var output = cacheItem.Output;
// Adds some caching information to the output if requested.
if (CacheSettings.DebugMode) {
@@ -447,10 +454,7 @@ namespace Orchard.OutputCache.Filters {
}
// Shorcut action execution.
filterContext.Result = new ContentResult {
Content = output,
ContentType = cacheItem.ContentType
};
filterContext.Result = new FileContentResult(cacheItem.Output, cacheItem.ContentType);
response.StatusCode = cacheItem.StatusCode;
@@ -463,18 +467,8 @@ namespace Orchard.OutputCache.Filters {
ApplyCacheControl(response);
// Intercept the rendered response output.
var originalWriter = response.Output;
var cachingWriter = new StringWriterWithEncoding(originalWriter.Encoding, originalWriter.FormatProvider);
_completeResponseFunc = (ctx) => {
ctx.HttpContext.Response.Output = originalWriter;
string capturedText = cachingWriter.ToString();
cachingWriter.Dispose();
ctx.HttpContext.Response.Write(capturedText);
return capturedText;
};
response.Output = cachingWriter;
// Remember that we should intercept the rendered response output.
_isCachingRequest = true;
}
private void ApplyCacheControl(HttpResponseBase response) {
@@ -488,9 +482,8 @@ namespace Orchard.OutputCache.Filters {
response.Cache.SetMaxAge(maxAge);
}
response.DisableUserCache();
// Keeping this example for later usage.
// response.DisableUserCache();
// response.DisableKernelCache();
// response.Cache.SetOmitVaryStar(true);
@@ -517,6 +510,16 @@ namespace Orchard.OutputCache.Filters {
}
}
private void ReleaseCacheKeyLock() {
if (_cacheKey != null) {
object cacheKeyLock;
if (_cacheKeyLocks.TryGetValue(_cacheKey, out cacheKeyLock) && Monitor.IsEntered(cacheKeyLock)) {
Logger.Debug("Releasing cache key lock for item '{0}'.", _cacheKey);
Monitor.Exit(cacheKeyLock);
}
}
}
protected virtual bool IsIgnoredUrl(string url, IEnumerable<string> ignoredUrls) {
if (ignoredUrls == null || !ignoredUrls.Any()) {
return false;
@@ -566,17 +569,4 @@ namespace Orchard.OutputCache.Filters {
public class ViewDataContainer : IViewDataContainer {
public ViewDataDictionary ViewData { get; set; }
}
public sealed class StringWriterWithEncoding : StringWriter {
private readonly Encoding encoding;
public StringWriterWithEncoding(Encoding encoding, IFormatProvider formatProvider)
: base(formatProvider) {
this.encoding = encoding;
}
public override Encoding Encoding {
get { return encoding; }
}
}
}

View File

@@ -6,7 +6,7 @@ namespace Orchard.OutputCache.Models {
public DateTime CachedOnUtc { get; set; }
public int Duration { get; set; }
public int GraceTime { get; set; }
public string Output { get; set; }
public byte[] Output { get; set; }
public string ContentType { get; set; }
public string QueryString { get; set; }
public string CacheKey { get; set; }

View File

@@ -12,7 +12,7 @@ namespace Orchard.OutputCache.Models {
public virtual int GraceTime { get; set; }
public virtual DateTime ValidUntilUtc { get; set; }
public virtual DateTime StoredUntilUtc { get; set; }
[StringLengthMax] public virtual string Output { get; set; }
public virtual byte[] Output { get; set; }
public virtual string ContentType { get; set; }
[StringLength(2048)] public virtual string QueryString { get; set; }
[StringLength(2048)] public virtual string CacheKey { get; set; }

View File

@@ -95,6 +95,7 @@
<Compile Include="AdminMenu.cs" />
<Compile Include="Controllers\AdminController.cs" />
<Compile Include="Controllers\StatisticsController.cs" />
<Compile Include="Filters\CaptureStream.cs" />
<Compile Include="Filters\OutputCacheFilter.cs" />
<Compile Include="Handlers\CacheSettingsPartHandler.cs" />
<Compile Include="Handlers\DisplayedContentItemHandler.cs" />

View File

@@ -27,7 +27,7 @@ namespace Orchard.SecureSocketsLayer.Filters {
public void OnActionExecuting(ActionExecutingContext filterContext) {
var settings = _sslService.GetSettings();
if (!settings.Enabled) {
if (filterContext.IsChildAction || !settings.Enabled) {
return;
}

View File

@@ -91,9 +91,10 @@
</system.web>
<system.webServer>
<!-- Prevent iis from only allowing integrated mode configuration. -->
<!-- Prevent IIS from only allowing integrated mode configuration. -->
<validation validateIntegratedModeConfiguration="false"/>
<modules runAllManagedModulesForAllRequests="false">
<remove name="OutputCache"/>
<remove name="WarmupHttpModule"/>
<add name="WarmupHttpModule" type="Orchard.WarmupStarter.WarmupHttpModule, Orchard.WarmupStarter, Version=1.8.1, Culture=neutral"/>
</modules>

View File

@@ -13,7 +13,7 @@ namespace Orchard.ContentManagement {
public class DefaultContentDisplay : IContentDisplay {
private readonly Lazy<IEnumerable<IContentHandler>> _handlers;
private readonly IShapeFactory _shapeFactory;
private readonly Lazy<IShapeTableLocator> _shapeTableLocator;
private readonly Lazy<IShapeTableLocator> _shapeTableLocator;
private readonly RequestContext _requestContext;
private readonly IVirtualPathProvider _virtualPathProvider;
@@ -22,7 +22,7 @@ namespace Orchard.ContentManagement {
public DefaultContentDisplay(
Lazy<IEnumerable<IContentHandler>> handlers,
IShapeFactory shapeFactory,
Lazy<IShapeTableLocator> shapeTableLocator,
Lazy<IShapeTableLocator> shapeTableLocator,
RequestContext requestContext,
IVirtualPathProvider virtualPathProvider,
IWorkContextAccessor workContextAccessor) {
@@ -74,13 +74,13 @@ namespace Orchard.ContentManagement {
// adding an alternate for [Stereotype]_Edit__[ContentType] e.g. Content-Menu.Edit
((IShape)itemShape).Metadata.Alternates.Add(actualShapeType + "__" + content.ContentItem.ContentType);
var context = new BuildEditorContext(itemShape, content, groupId, _shapeFactory);
BindPlacement(context, null, stereotype);
_handlers.Value.Invoke(handler => handler.BuildEditor(context), Logger);
return context.Shape;
}
@@ -107,7 +107,7 @@ namespace Orchard.ContentManagement {
BindPlacement(context, null, stereotype);
_handlers.Value.Invoke(handler => handler.UpdateEditor(context), Logger);
return context.Shape;
}
@@ -131,7 +131,7 @@ namespace Orchard.ContentManagement {
Stereotype = stereotype,
DisplayType = displayType,
Differentiator = differentiator,
Path = GetPath()
Path = GetPath()
};
// define which location should be used if none placement is hit
@@ -154,8 +154,7 @@ namespace Orchard.ContentManagement {
/// <summary>
/// Gets the current app-relative path, i.e. ~/my-blog/foo.
/// </summary>
private string GetPath()
{
private string GetPath() {
return VirtualPathUtility.AppendTrailingSlash(_virtualPathProvider.ToAppRelative(_requestContext.HttpContext.Request.Path));
}
}

View File

@@ -169,6 +169,8 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy {
context.ViewContext.ViewData = new ViewDataDictionary(context.Value);
context.ViewContext.TempData = new TempDataDictionary();
context.ViewContext.View = viewResult.View;
context.ViewContext.RouteData = controllerContext.RouteData;
context.ViewContext.RequestContext.RouteData = controllerContext.RouteData;
viewResult.View.Render(context.ViewContext, sw);
viewResult.ViewEngine.ReleaseView(controllerContext, viewResult.View);
return new HtmlString(sw.GetStringBuilder().ToString());

View File

@@ -29,9 +29,9 @@ namespace Orchard.Localization.Services {
.Select(c => c.GetCulture(httpContext))
.Where(c => c != null)
.OrderByDescending(c => c.Priority)
.FirstOrDefault(c => !string.IsNullOrEmpty(c.CultureName));
.FirstOrDefault(c => !String.IsNullOrEmpty(c.CultureName));
return culture == null ? string.Empty : culture.CultureName;
return culture == null ? String.Empty : culture.CultureName;
}
}
}

View File

@@ -9,18 +9,17 @@ using Orchard.Localization.Records;
namespace Orchard.Localization.Services {
public class DefaultCultureManager : ICultureManager {
private readonly IRepository<CultureRecord> _cultureRepository;
private readonly IEnumerable<ICultureSelector> _cultureSelectors;
private readonly ISignals _signals;
private readonly IWorkContextAccessor _workContextAccessor;
private readonly ICacheManager _cacheManager;
public DefaultCultureManager(IRepository<CultureRecord> cultureRepository,
IEnumerable<ICultureSelector> cultureSelectors,
ISignals signals,
IWorkContextAccessor workContextAccessor,
ICacheManager cacheManager) {
public DefaultCultureManager(
IRepository<CultureRecord> cultureRepository,
ISignals signals,
IWorkContextAccessor workContextAccessor,
ICacheManager cacheManager) {
_cultureRepository = cultureRepository;
_cultureSelectors = cultureSelectors;
_signals = signals;
_workContextAccessor = workContextAccessor;
_cacheManager = cacheManager;
@@ -38,12 +37,12 @@ namespace Orchard.Localization.Services {
if (!IsValidCulture(cultureName)) {
throw new ArgumentException("cultureName");
}
if (ListCultures().Any(culture => culture == cultureName)) {
return;
}
_cultureRepository.Create(new CultureRecord {Culture = cultureName});
_cultureRepository.Create(new CultureRecord { Culture = cultureName });
_signals.Trigger("culturesChanged");
}
@@ -81,7 +80,7 @@ namespace Orchard.Localization.Services {
public bool IsValidCulture(string cultureName) {
var segments = cultureName.Split('-');
if(segments.Length == 0) {
if (segments.Length == 0) {
return false;
}
@@ -92,7 +91,7 @@ namespace Orchard.Localization.Services {
if (segments.Any(s => s.Length < 2)) {
return false;
}
return true;
}
}

View File

@@ -4,19 +4,19 @@ using System.Web;
namespace Orchard.Mvc {
public interface IHttpContextAccessor {
HttpContextBase Current();
void Set(HttpContextBase stub);
void Set(HttpContextBase httpContext);
}
public class HttpContextAccessor : IHttpContextAccessor {
private HttpContextBase _stub;
private HttpContextBase _httpContext;
public HttpContextBase Current() {
var httpContext = GetStaticProperty();
return httpContext != null ? new HttpContextWrapper(httpContext) : _stub;
return httpContext != null ? new HttpContextWrapper(httpContext) : _httpContext;
}
public void Set(HttpContextBase stub) {
_stub = stub;
public void Set(HttpContextBase httpContext) {
_httpContext = httpContext;
}
private HttpContext GetStaticProperty() {

View File

@@ -83,7 +83,7 @@ namespace Orchard.Mvc {
}
/// <summary>
/// standin context for background tasks.
/// Standin context for background tasks.
/// </summary>
class HttpContextPlaceholder : HttpContextBase {
private readonly Lazy<string> _baseUrl;
@@ -124,6 +124,12 @@ namespace Orchard.Mvc {
public override string ApplyAppPathModifier(string virtualPath) {
return virtualPath;
}
public override HttpCookieCollection Cookies {
get {
return new HttpCookieCollection();
}
}
}
/// <summary>
@@ -158,7 +164,7 @@ namespace Orchard.Mvc {
public override NameValueCollection Headers {
get {
return new NameValueCollection {{"Host", _uri.Authority}};
return new NameValueCollection { { "Host", _uri.Authority } };
}
}
@@ -184,10 +190,44 @@ namespace Orchard.Mvc {
}
}
public override HttpCookieCollection Cookies {
get {
return new HttpCookieCollection();
}
}
public override bool IsLocal {
get { return true; }
}
public override string Path {
get { return "/"; }
}
public override string UserAgent {
get {
return "Placeholder";
}
}
public override HttpBrowserCapabilitiesBase Browser {
get {
return new HttpBrowserCapabilitiesPlaceholder();
}
}
}
class HttpBrowserCapabilitiesPlaceholder : HttpBrowserCapabilitiesBase {
public override string this[string key] {
get {
return "";
}
}
public override bool IsMobileDevice { get { return false; } }
public override string Browser { get { return "Placeholder"; } }
public override bool Cookies { get { return true; } }
public override ArrayList Browsers { get { return new ArrayList(); } }
}
}
}

View File

@@ -24,7 +24,7 @@ namespace Orchard {
/// <returns>True if the dependency could be resolved, false otherwise</returns>
public abstract bool TryResolve<T>(out T service);
public abstract T GetState<T>(string name);
public abstract T GetState<T>(string name);
public abstract void SetState<T>(string name, T value);
/// <summary>