mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Revert "Cherry picked ce630f980c7a79ae17b36598f3834c4ffd523739."
This reverts commit aba53e122d
.
Conflicts:
src/Orchard.Web/Modules/Orchard.Layouts/Handlers/LayoutPartHandler.cs
src/Orchard/Mvc/HttpContextAccessor.cs
src/Orchard/Mvc/IHttpContextAccessor.cs
src/Orchard/Mvc/MvcModule.cs
src/Orchard/Orchard.Framework.csproj
src/Orchard/Tasks/BackgroundService.cs
This commit is contained in:
@@ -28,13 +28,6 @@ namespace Orchard.Tests.Environment {
|
|||||||
container.Mock<IHttpContextAccessor>()
|
container.Mock<IHttpContextAccessor>()
|
||||||
.Setup(x => x.Current())
|
.Setup(x => x.Current())
|
||||||
.Returns(() => _httpContextCurrent);
|
.Returns(() => _httpContextCurrent);
|
||||||
|
|
||||||
container.Mock<IHttpContextAccessor>()
|
|
||||||
.Setup(x => x.CreateContext(It.IsAny<ILifetimeScope>()))
|
|
||||||
.Returns(() => new StubHttpContext());
|
|
||||||
|
|
||||||
container.Mock<IWorkContextEvents>()
|
|
||||||
.Setup(x => x.Started());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@@ -56,11 +56,7 @@ namespace Orchard.Tests.Environment.ShellBuilders {
|
|||||||
|
|
||||||
_container.Mock<IHttpContextAccessor>()
|
_container.Mock<IHttpContextAccessor>()
|
||||||
.Setup(x => x.Current())
|
.Setup(x => x.Current())
|
||||||
.Returns(httpContext);
|
.Returns(default(HttpContextBase));
|
||||||
|
|
||||||
_container.Mock<IHttpContextAccessor>()
|
|
||||||
.Setup(x => x.CreateContext(It.IsAny<ILifetimeScope>()))
|
|
||||||
.Returns(httpContext);
|
|
||||||
|
|
||||||
var factory = _container.Resolve<IShellContextFactory>();
|
var factory = _container.Resolve<IShellContextFactory>();
|
||||||
|
|
||||||
|
@@ -43,10 +43,6 @@ namespace Orchard.Tests.Environment.State {
|
|||||||
_container.Mock<IHttpContextAccessor>()
|
_container.Mock<IHttpContextAccessor>()
|
||||||
.Setup(x=>x.Current())
|
.Setup(x=>x.Current())
|
||||||
.Returns(httpContext);
|
.Returns(httpContext);
|
||||||
_container.Mock<IHttpContextAccessor>()
|
|
||||||
.Setup(x => x.CreateContext(It.IsAny<ILifetimeScope>()))
|
|
||||||
.Returns(httpContext);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[TearDown]
|
[TearDown]
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
using System.Web;
|
using System.Web;
|
||||||
using Autofac;
|
|
||||||
using Orchard.Mvc;
|
using Orchard.Mvc;
|
||||||
|
|
||||||
namespace Orchard.Tests.Stubs {
|
namespace Orchard.Tests.Stubs {
|
||||||
@@ -17,10 +16,6 @@ namespace Orchard.Tests.Stubs {
|
|||||||
return _httpContext;
|
return _httpContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpContextBase CreateContext(ILifetimeScope lifetimeScope) {
|
|
||||||
return _httpContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Set(HttpContextBase httpContext) {
|
public void Set(HttpContextBase httpContext) {
|
||||||
_httpContext = httpContext;
|
_httpContext = httpContext;
|
||||||
}
|
}
|
||||||
|
@@ -23,10 +23,6 @@ namespace Orchard.Tests.Tasks {
|
|||||||
.Setup(x => x.Current())
|
.Setup(x => x.Current())
|
||||||
.Returns(() => null);
|
.Returns(() => null);
|
||||||
|
|
||||||
container.Mock<IHttpContextAccessor>()
|
|
||||||
.Setup(x => x.CreateContext(It.IsAny<ILifetimeScope>()))
|
|
||||||
.Returns(() => new StubHttpContext());
|
|
||||||
|
|
||||||
container.Mock<IWorkContextEvents>()
|
container.Mock<IWorkContextEvents>()
|
||||||
.Setup(x => x.Started());
|
.Setup(x => x.Started());
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,11 @@
|
|||||||
using Orchard.ContentManagement.MetaData;
|
using Orchard.ContentManagement;
|
||||||
|
using Orchard.ContentManagement.MetaData;
|
||||||
using Orchard.Core.Contents.Extensions;
|
using Orchard.Core.Contents.Extensions;
|
||||||
using Orchard.Data.Migration;
|
using Orchard.Data.Migration;
|
||||||
|
|
||||||
namespace Orchard.Autoroute {
|
namespace Orchard.Autoroute {
|
||||||
public class Migrations : DataMigrationImpl {
|
public class Migrations : DataMigrationImpl {
|
||||||
|
|
||||||
public int Create() {
|
public int Create() {
|
||||||
SchemaBuilder.CreateTable("AutoroutePartRecord",
|
SchemaBuilder.CreateTable("AutoroutePartRecord",
|
||||||
table => table
|
table => table
|
||||||
|
@@ -16,7 +16,6 @@ namespace Orchard.Layouts.Handlers {
|
|||||||
private readonly IContentPartDisplay _contentPartDisplay;
|
private readonly IContentPartDisplay _contentPartDisplay;
|
||||||
private readonly IShapeDisplay _shapeDisplay;
|
private readonly IShapeDisplay _shapeDisplay;
|
||||||
private readonly ILayoutSerializer _serializer;
|
private readonly ILayoutSerializer _serializer;
|
||||||
private readonly IStaticHttpContextScopeFactory _staticHttpContextScopeFactory;
|
|
||||||
private readonly IAliasService _aliasService;
|
private readonly IAliasService _aliasService;
|
||||||
|
|
||||||
public LayoutPartHandler(
|
public LayoutPartHandler(
|
||||||
@@ -26,7 +25,6 @@ namespace Orchard.Layouts.Handlers {
|
|||||||
IContentPartDisplay contentPartDisplay,
|
IContentPartDisplay contentPartDisplay,
|
||||||
IShapeDisplay shapeDisplay,
|
IShapeDisplay shapeDisplay,
|
||||||
ILayoutSerializer serializer,
|
ILayoutSerializer serializer,
|
||||||
IStaticHttpContextScopeFactory staticHttpContextScopeFactory,
|
|
||||||
IAliasService aliasService) {
|
IAliasService aliasService) {
|
||||||
|
|
||||||
_layoutManager = layoutManager;
|
_layoutManager = layoutManager;
|
||||||
@@ -34,7 +32,6 @@ namespace Orchard.Layouts.Handlers {
|
|||||||
_contentPartDisplay = contentPartDisplay;
|
_contentPartDisplay = contentPartDisplay;
|
||||||
_shapeDisplay = shapeDisplay;
|
_shapeDisplay = shapeDisplay;
|
||||||
_serializer = serializer;
|
_serializer = serializer;
|
||||||
_staticHttpContextScopeFactory = staticHttpContextScopeFactory;
|
|
||||||
_aliasService = aliasService;
|
_aliasService = aliasService;
|
||||||
|
|
||||||
Filters.Add(StorageFilter.For(repository));
|
Filters.Add(StorageFilter.For(repository));
|
||||||
@@ -44,22 +41,13 @@ namespace Orchard.Layouts.Handlers {
|
|||||||
|
|
||||||
private void IndexLayout(IndexContentContext context, LayoutPart part) {
|
private void IndexLayout(IndexContentContext context, LayoutPart part) {
|
||||||
var layoutShape = _contentPartDisplay.BuildDisplay(part);
|
var layoutShape = _contentPartDisplay.BuildDisplay(part);
|
||||||
var layoutHtml = RenderShape(layoutShape);
|
var layoutHtml = _shapeDisplay.Display(layoutShape);
|
||||||
|
|
||||||
context.DocumentIndex
|
context.DocumentIndex
|
||||||
.Add("body", layoutHtml).RemoveTags().Analyze()
|
.Add("body", layoutHtml).RemoveTags().Analyze()
|
||||||
.Add("format", "html").Store();
|
.Add("format", "html").Store();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This method of rendering is safe even in background tasks.
|
|
||||||
/// </summary>
|
|
||||||
private string RenderShape(dynamic shape) {
|
|
||||||
using (_staticHttpContextScopeFactory.CreateStaticScope()) {
|
|
||||||
return _shapeDisplay.Display(shape);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateTemplateClients(PublishContentContext context, LayoutPart part) {
|
private void UpdateTemplateClients(PublishContentContext context, LayoutPart part) {
|
||||||
UpdateTemplateClients(part);
|
UpdateTemplateClients(part);
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Web;
|
||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
using System.Web.UI;
|
using System.Web.UI;
|
||||||
using System.Web.WebPages;
|
using System.Web.WebPages;
|
||||||
@@ -14,6 +15,7 @@ namespace Orchard.Templates.Services {
|
|||||||
[OrchardFeature("Orchard.Templates.Razor")]
|
[OrchardFeature("Orchard.Templates.Razor")]
|
||||||
public class RazorTemplateProcessor : TemplateProcessorImpl {
|
public class RazorTemplateProcessor : TemplateProcessorImpl {
|
||||||
private readonly IRazorCompiler _compiler;
|
private readonly IRazorCompiler _compiler;
|
||||||
|
private readonly HttpContextBase _httpContextBase;
|
||||||
private readonly IWorkContextAccessor _wca;
|
private readonly IWorkContextAccessor _wca;
|
||||||
|
|
||||||
public override string Type {
|
public override string Type {
|
||||||
@@ -22,9 +24,11 @@ namespace Orchard.Templates.Services {
|
|||||||
|
|
||||||
public RazorTemplateProcessor(
|
public RazorTemplateProcessor(
|
||||||
IRazorCompiler compiler,
|
IRazorCompiler compiler,
|
||||||
|
HttpContextBase httpContextBase,
|
||||||
IWorkContextAccessor wca) {
|
IWorkContextAccessor wca) {
|
||||||
|
|
||||||
_compiler = compiler;
|
_compiler = compiler;
|
||||||
|
_httpContextBase = httpContextBase;
|
||||||
_wca = wca;
|
_wca = wca;
|
||||||
Logger = NullLogger.Instance;
|
Logger = NullLogger.Instance;
|
||||||
}
|
}
|
||||||
@@ -37,7 +41,7 @@ namespace Orchard.Templates.Services {
|
|||||||
|
|
||||||
public override string Process(string template, string name, DisplayContext context = null, dynamic model = null) {
|
public override string Process(string template, string name, DisplayContext context = null, dynamic model = null) {
|
||||||
if (String.IsNullOrEmpty(template))
|
if (String.IsNullOrEmpty(template))
|
||||||
return String.Empty;
|
return string.Empty;
|
||||||
|
|
||||||
var compiledTemplate = _compiler.CompileRazor(template, name, new Dictionary<string, object>());
|
var compiledTemplate = _compiler.CompileRazor(template, name, new Dictionary<string, object>());
|
||||||
var result = ActivateAndRenderTemplate(compiledTemplate, context, null, model);
|
var result = ActivateAndRenderTemplate(compiledTemplate, context, null, model);
|
||||||
@@ -69,10 +73,9 @@ namespace Orchard.Templates.Services {
|
|||||||
// Setup a fake view context in order to support razor syntax inside of HTML attributes,
|
// Setup a fake view context in order to support razor syntax inside of HTML attributes,
|
||||||
// for instance: <a href="@WorkContext.CurrentSite.BaseUrl">Homepage</a>.
|
// for instance: <a href="@WorkContext.CurrentSite.BaseUrl">Homepage</a>.
|
||||||
var viewData = new ViewDataDictionary(model);
|
var viewData = new ViewDataDictionary(model);
|
||||||
var httpContext = _wca.GetContext().HttpContext;
|
|
||||||
obj.ViewContext = new ViewContext(
|
obj.ViewContext = new ViewContext(
|
||||||
new ControllerContext(
|
new ControllerContext(
|
||||||
httpContext.Request.RequestContext,
|
_httpContextBase.Request.RequestContext,
|
||||||
new StubController()),
|
new StubController()),
|
||||||
new StubView(),
|
new StubView(),
|
||||||
viewData,
|
viewData,
|
||||||
@@ -80,7 +83,7 @@ namespace Orchard.Templates.Services {
|
|||||||
htmlWriter);
|
htmlWriter);
|
||||||
|
|
||||||
obj.ViewData = viewData;
|
obj.ViewData = viewData;
|
||||||
obj.WebPageContext = new WebPageContext(httpContext, obj as WebPageRenderingBase, model);
|
obj.WebPageContext = new WebPageContext(_httpContextBase, obj as WebPageRenderingBase, model);
|
||||||
obj.WorkContext = _wca.GetContext();
|
obj.WorkContext = _wca.GetContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -179,8 +179,8 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy {
|
|||||||
|
|
||||||
private ControllerContext CreateControllerContext() {
|
private ControllerContext CreateControllerContext() {
|
||||||
var controller = new StubController();
|
var controller = new StubController();
|
||||||
var httpContext = _workContextAccessor.GetContext().HttpContext;
|
var httpContext = _workContextAccessor.GetContext().Resolve<HttpContextBase>();
|
||||||
var requestContext = httpContext.Request.RequestContext;
|
var requestContext = _workContextAccessor.GetContext().Resolve<RequestContext>();
|
||||||
var routeData = requestContext.RouteData;
|
var routeData = requestContext.RouteData;
|
||||||
|
|
||||||
routeData.DataTokens["IWorkContextAccessor"] = _workContextAccessor;
|
routeData.DataTokens["IWorkContextAccessor"] = _workContextAccessor;
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Web;
|
||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
|
using System.Web.Routing;
|
||||||
using Orchard.DisplayManagement.Implementation;
|
using Orchard.DisplayManagement.Implementation;
|
||||||
using Orchard.DisplayManagement.Shapes;
|
using Orchard.DisplayManagement.Shapes;
|
||||||
|
|
||||||
@@ -8,24 +10,28 @@ namespace Orchard.DisplayManagement {
|
|||||||
public class ShapeDisplay : IShapeDisplay {
|
public class ShapeDisplay : IShapeDisplay {
|
||||||
private readonly IDisplayHelperFactory _displayHelperFactory;
|
private readonly IDisplayHelperFactory _displayHelperFactory;
|
||||||
private readonly IWorkContextAccessor _workContextAccessor;
|
private readonly IWorkContextAccessor _workContextAccessor;
|
||||||
|
private readonly HttpContextBase _httpContextBase;
|
||||||
|
private readonly RequestContext _requestContext;
|
||||||
|
|
||||||
public ShapeDisplay(
|
public ShapeDisplay(
|
||||||
IDisplayHelperFactory displayHelperFactory,
|
IDisplayHelperFactory displayHelperFactory,
|
||||||
IWorkContextAccessor workContextAccessor) {
|
IWorkContextAccessor workContextAccessor,
|
||||||
|
HttpContextBase httpContextBase,
|
||||||
|
RequestContext requestContext) {
|
||||||
_displayHelperFactory = displayHelperFactory;
|
_displayHelperFactory = displayHelperFactory;
|
||||||
_workContextAccessor = workContextAccessor;
|
_workContextAccessor = workContextAccessor;
|
||||||
|
_httpContextBase = httpContextBase;
|
||||||
|
_requestContext = requestContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Display(Shape shape) {
|
public string Display(Shape shape) {
|
||||||
return Display((object)shape);
|
return Display((object) shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Display(object shape) {
|
public string Display(object shape) {
|
||||||
var workContext = _workContextAccessor.GetContext();
|
|
||||||
var httpContext = workContext.HttpContext;
|
|
||||||
var viewContext = new ViewContext {
|
var viewContext = new ViewContext {
|
||||||
HttpContext = httpContext,
|
HttpContext = _httpContextBase,
|
||||||
RequestContext = httpContext.Request.RequestContext
|
RequestContext = _requestContext
|
||||||
};
|
};
|
||||||
viewContext.RouteData.DataTokens["IWorkContextAccessor"] = _workContextAccessor;
|
viewContext.RouteData.DataTokens["IWorkContextAccessor"] = _workContextAccessor;
|
||||||
var display = _displayHelperFactory.CreateHelper(viewContext, new ViewDataContainer());
|
var display = _displayHelperFactory.CreateHelper(viewContext, new ViewDataContainer());
|
||||||
|
@@ -63,7 +63,7 @@ namespace Orchard.Environment {
|
|||||||
builder.RegisterType<AppDomainAssemblyNameResolver>().As<IAssemblyNameResolver>().SingleInstance();
|
builder.RegisterType<AppDomainAssemblyNameResolver>().As<IAssemblyNameResolver>().SingleInstance();
|
||||||
builder.RegisterType<GacAssemblyNameResolver>().As<IAssemblyNameResolver>().SingleInstance();
|
builder.RegisterType<GacAssemblyNameResolver>().As<IAssemblyNameResolver>().SingleInstance();
|
||||||
builder.RegisterType<OrchardFrameworkAssemblyNameResolver>().As<IAssemblyNameResolver>().SingleInstance();
|
builder.RegisterType<OrchardFrameworkAssemblyNameResolver>().As<IAssemblyNameResolver>().SingleInstance();
|
||||||
builder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>().SingleInstance();
|
builder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>().InstancePerDependency();
|
||||||
builder.RegisterType<ViewsBackgroundCompilation>().As<IViewsBackgroundCompilation>().SingleInstance();
|
builder.RegisterType<ViewsBackgroundCompilation>().As<IViewsBackgroundCompilation>().SingleInstance();
|
||||||
builder.RegisterType<DefaultExceptionPolicy>().As<IExceptionPolicy>().SingleInstance();
|
builder.RegisterType<DefaultExceptionPolicy>().As<IExceptionPolicy>().SingleInstance();
|
||||||
builder.RegisterType<DefaultCriticalErrorProvider>().As<ICriticalErrorProvider>().SingleInstance();
|
builder.RegisterType<DefaultCriticalErrorProvider>().As<ICriticalErrorProvider>().SingleInstance();
|
||||||
|
@@ -60,14 +60,11 @@ namespace Orchard.Environment {
|
|||||||
return CreateWorkContextScope(httpContext);
|
return CreateWorkContextScope(httpContext);
|
||||||
|
|
||||||
var workLifetime = _lifetimeScope.BeginLifetimeScope("work");
|
var workLifetime = _lifetimeScope.BeginLifetimeScope("work");
|
||||||
httpContext = _httpContextAccessor.CreateContext(workLifetime);
|
|
||||||
workLifetime.Resolve<WorkContextProperty<HttpContextBase>>().Value = httpContext;
|
|
||||||
|
|
||||||
var events = workLifetime.Resolve<IEnumerable<IWorkContextEvents>>();
|
var events = workLifetime.Resolve<IEnumerable<IWorkContextEvents>>();
|
||||||
events.Invoke(e => e.Started(), NullLogger.Instance);
|
events.Invoke(e => e.Started(), NullLogger.Instance);
|
||||||
|
|
||||||
return new ThreadStaticScopeImplementation(
|
return new ThreadStaticScopeImplementation(
|
||||||
httpContext,
|
|
||||||
events,
|
events,
|
||||||
workLifetime,
|
workLifetime,
|
||||||
EnsureThreadStaticContexts(),
|
EnsureThreadStaticContexts(),
|
||||||
@@ -116,9 +113,8 @@ namespace Orchard.Environment {
|
|||||||
readonly WorkContext _workContext;
|
readonly WorkContext _workContext;
|
||||||
readonly Action _disposer;
|
readonly Action _disposer;
|
||||||
|
|
||||||
public ThreadStaticScopeImplementation(HttpContextBase httpContext, IEnumerable<IWorkContextEvents> events, ILifetimeScope lifetimeScope, ConcurrentDictionary<object, WorkContext> contexts, object workContextKey) {
|
public ThreadStaticScopeImplementation(IEnumerable<IWorkContextEvents> events, ILifetimeScope lifetimeScope, ConcurrentDictionary<object, WorkContext> contexts, object workContextKey) {
|
||||||
_workContext = lifetimeScope.Resolve<WorkContext>();
|
_workContext = lifetimeScope.Resolve<WorkContext>();
|
||||||
httpContext.Items[workContextKey] = _workContext;
|
|
||||||
contexts.AddOrUpdate(workContextKey, _workContext, (a, b) => _workContext);
|
contexts.AddOrUpdate(workContextKey, _workContext, (a, b) => _workContext);
|
||||||
|
|
||||||
_disposer = () => {
|
_disposer = () => {
|
||||||
@@ -127,11 +123,6 @@ namespace Orchard.Environment {
|
|||||||
WorkContext removedContext;
|
WorkContext removedContext;
|
||||||
contexts.TryRemove(workContextKey, out removedContext);
|
contexts.TryRemove(workContextKey, out removedContext);
|
||||||
lifetimeScope.Dispose();
|
lifetimeScope.Dispose();
|
||||||
|
|
||||||
var staticHttpContext = httpContext as IDisposable;
|
|
||||||
|
|
||||||
if(staticHttpContext != null)
|
|
||||||
staticHttpContext.Dispose();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,15 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Orchard {
|
|
||||||
/// <summary>
|
|
||||||
/// A factory class that creates an <see cref="StaticHttpContextScope"/> instance and initializes the HttpContext.Current property with that instance until the scope is disposed of.
|
|
||||||
/// This is useful when rendering views from a background thread, as some Html Helpers access HttpContext.Current directly, thus preventing a NullReferenceException.
|
|
||||||
/// </summary>
|
|
||||||
public interface IStaticHttpContextScopeFactory : IDependency {
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a disposable static HttpContext scope. This is safe to use even if there is an actual HttpContext.Current instance.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
IDisposable CreateStaticScope();
|
|
||||||
}
|
|
||||||
}
|
|
9
src/Orchard/Mvc/Extensions/HttpContextBaseExtensions.cs
Normal file
9
src/Orchard/Mvc/Extensions/HttpContextBaseExtensions.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using System.Web;
|
||||||
|
|
||||||
|
namespace Orchard.Mvc.Extensions {
|
||||||
|
public static class HttpContextBaseExtensions {
|
||||||
|
public static bool IsBackgroundContext(this HttpContextBase httpContextBase) {
|
||||||
|
return httpContextBase == null || httpContextBase is MvcModule.HttpContextPlaceholder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,13 +0,0 @@
|
|||||||
using System.Web;
|
|
||||||
|
|
||||||
namespace Orchard.Mvc.Extensions {
|
|
||||||
public static class HttpContextExtensions {
|
|
||||||
public static bool IsBackgroundContext(this HttpContextBase httpContext) {
|
|
||||||
return httpContext == null || httpContext is MvcModule.HttpContextPlaceholder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsBackgroundContext(this HttpContext httpContext) {
|
|
||||||
return httpContext == null || httpContext.Items.Contains(StaticHttpContextScopeFactory.IsBackgroundHttpContextKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,40 +1,39 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using Autofac;
|
|
||||||
using Orchard.Mvc.Extensions;
|
|
||||||
using Orchard.Settings;
|
|
||||||
|
|
||||||
namespace Orchard.Mvc {
|
namespace Orchard.Mvc {
|
||||||
public class HttpContextAccessor : IHttpContextAccessor {
|
public class HttpContextAccessor : IHttpContextAccessor {
|
||||||
readonly object _contextKey = new object();
|
private HttpContextBase _httpContext;
|
||||||
|
|
||||||
[ThreadStatic]
|
|
||||||
static ConcurrentDictionary<object, HttpContextBase> _threadStaticContexts;
|
|
||||||
|
|
||||||
public HttpContextBase Current() {
|
public HttpContextBase Current() {
|
||||||
if (!HttpContext.Current.IsBackgroundContext())
|
var httpContext = GetStaticProperty();
|
||||||
return new HttpContextWrapper(HttpContext.Current);
|
return !IsBackgroundHttpContext(httpContext) ? new HttpContextWrapper(httpContext) : _httpContext;
|
||||||
|
|
||||||
return GetContext();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpContextBase CreateContext(ILifetimeScope lifetimeScope) {
|
public void Set(HttpContextBase httpContext) {
|
||||||
return new MvcModule.HttpContextPlaceholder(_threadStaticContexts, _contextKey, () => {
|
_httpContext = httpContext;
|
||||||
var baseUrl = lifetimeScope.Resolve<ISiteService>().GetSiteSettings().BaseUrl;
|
|
||||||
return !String.IsNullOrEmpty(baseUrl) ? baseUrl : "http://localhost"; // Return a valid URL always.
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private HttpContextBase GetContext() {
|
private static bool IsBackgroundHttpContext(HttpContext httpContext) {
|
||||||
HttpContextBase context;
|
return httpContext == null || httpContext.Items.Contains(BackgroundHttpContextFactory.IsBackgroundHttpContextKey);
|
||||||
return ThreadStaticContexts.TryGetValue(_contextKey, out context) ? context : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConcurrentDictionary<object, HttpContextBase> ThreadStaticContexts {
|
private static HttpContext GetStaticProperty() {
|
||||||
get {
|
var httpContext = HttpContext.Current;
|
||||||
return _threadStaticContexts ?? (_threadStaticContexts = new ConcurrentDictionary<object, HttpContextBase>());
|
if (httpContext == null) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// The "Request" property throws at application startup on IIS integrated pipeline mode.
|
||||||
|
if (httpContext.Request == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return httpContext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,9 +1,8 @@
|
|||||||
using System.Web;
|
using System.Web;
|
||||||
using Autofac;
|
|
||||||
|
|
||||||
namespace Orchard.Mvc {
|
namespace Orchard.Mvc {
|
||||||
public interface IHttpContextAccessor {
|
public interface IHttpContextAccessor {
|
||||||
HttpContextBase Current();
|
HttpContextBase Current();
|
||||||
HttpContextBase CreateContext(ILifetimeScope lifetimeScope);
|
void Set(HttpContextBase httpContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
@@ -10,7 +9,6 @@ using System.Web.Instrumentation;
|
|||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
using System.Web.Routing;
|
using System.Web.Routing;
|
||||||
using Autofac;
|
using Autofac;
|
||||||
using Orchard.Mvc.Extensions;
|
|
||||||
using Orchard.Mvc.Routes;
|
using Orchard.Mvc.Routes;
|
||||||
using Orchard.Settings;
|
using Orchard.Settings;
|
||||||
|
|
||||||
@@ -52,7 +50,7 @@ namespace Orchard.Mvc {
|
|||||||
// which requires activating the Site content item, which in turn requires a UrlHelper, which in turn requires a RequestContext,
|
// which requires activating the Site content item, which in turn requires a UrlHelper, which in turn requires a RequestContext,
|
||||||
// thus preventing a StackOverflowException.
|
// thus preventing a StackOverflowException.
|
||||||
var baseUrl = new Func<string>(() => siteService.GetSiteSettings().BaseUrl);
|
var baseUrl = new Func<string>(() => siteService.GetSiteSettings().BaseUrl);
|
||||||
var httpContextBase = context.Resolve<IHttpContextAccessor>().Current();
|
var httpContextBase = new HttpContextPlaceholder(baseUrl);
|
||||||
|
|
||||||
if (httpContextBase == null) {
|
if (httpContextBase == null) {
|
||||||
context.Resolve<IWorkContextAccessor>().CreateWorkContextScope();
|
context.Resolve<IWorkContextAccessor>().CreateWorkContextScope();
|
||||||
@@ -66,7 +64,7 @@ namespace Orchard.Mvc {
|
|||||||
static RequestContext RequestContextFactory(IComponentContext context) {
|
static RequestContext RequestContextFactory(IComponentContext context) {
|
||||||
var httpContextAccessor = context.Resolve<IHttpContextAccessor>();
|
var httpContextAccessor = context.Resolve<IHttpContextAccessor>();
|
||||||
var httpContext = httpContextAccessor.Current();
|
var httpContext = httpContextAccessor.Current();
|
||||||
if (!httpContext.IsBackgroundContext()) {
|
if (httpContext != null) {
|
||||||
|
|
||||||
var mvcHandler = httpContext.Handler as MvcHandler;
|
var mvcHandler = httpContext.Handler as MvcHandler;
|
||||||
if (mvcHandler != null) {
|
if (mvcHandler != null) {
|
||||||
@@ -93,23 +91,16 @@ namespace Orchard.Mvc {
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Standin context for background tasks.
|
/// Standin context for background tasks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class HttpContextPlaceholder : HttpContextBase, IDisposable {
|
public class HttpContextPlaceholder : HttpContextBase {
|
||||||
private readonly Lazy<string> _baseUrl;
|
private readonly Lazy<string> _baseUrl;
|
||||||
private readonly IDictionary _items = new Dictionary<object, object>();
|
private readonly IDictionary _items = new Dictionary<object, object>();
|
||||||
readonly Action _disposer;
|
|
||||||
|
|
||||||
public HttpContextPlaceholder(ConcurrentDictionary<object, HttpContextBase> contexts, object contextKey, Func<string> baseUrl) {
|
public HttpContextPlaceholder(Func<string> baseUrl) {
|
||||||
_baseUrl = new Lazy<string>(baseUrl);
|
_baseUrl = new Lazy<string>(baseUrl);
|
||||||
contexts.AddOrUpdate(contextKey, this, (a, b) => this);
|
|
||||||
|
|
||||||
_disposer = () => {
|
|
||||||
HttpContextBase removedContext;
|
|
||||||
contexts.TryRemove(contextKey, out removedContext);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override HttpRequestBase Request {
|
public override HttpRequestBase Request {
|
||||||
get { return new HttpRequestPlaceholder(this, new Uri(_baseUrl.Value)); }
|
get { return new HttpRequestPlaceholder(new Uri(_baseUrl.Value)); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IHttpHandler Handler { get; set; }
|
public override IHttpHandler Handler { get; set; }
|
||||||
@@ -118,10 +109,6 @@ namespace Orchard.Mvc {
|
|||||||
get { return new HttpResponsePlaceholder(); }
|
get { return new HttpResponsePlaceholder(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public override HttpSessionStateBase Session {
|
|
||||||
get { return null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IDictionary Items {
|
public override IDictionary Items {
|
||||||
get { return _items; }
|
get { return _items; }
|
||||||
}
|
}
|
||||||
@@ -137,10 +124,6 @@ namespace Orchard.Mvc {
|
|||||||
public override object GetService(Type serviceType) {
|
public override object GetService(Type serviceType) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose() {
|
|
||||||
_disposer();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HttpResponsePlaceholder : HttpResponseBase {
|
public class HttpResponsePlaceholder : HttpResponseBase {
|
||||||
@@ -159,12 +142,9 @@ namespace Orchard.Mvc {
|
|||||||
/// standin context for background tasks.
|
/// standin context for background tasks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class HttpRequestPlaceholder : HttpRequestBase {
|
public class HttpRequestPlaceholder : HttpRequestBase {
|
||||||
private readonly HttpContextBase _httpContext;
|
|
||||||
private readonly Uri _uri;
|
private readonly Uri _uri;
|
||||||
private RequestContext _requestContext;
|
|
||||||
|
|
||||||
public HttpRequestPlaceholder(HttpContextBase httpContext, Uri uri) {
|
public HttpRequestPlaceholder(Uri uri) {
|
||||||
_httpContext = httpContext;
|
|
||||||
_uri = uri;
|
_uri = uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +203,7 @@ namespace Orchard.Mvc {
|
|||||||
return new NameValueCollection {
|
return new NameValueCollection {
|
||||||
{ "SERVER_PORT", _uri.Port.ToString(CultureInfo.InvariantCulture) },
|
{ "SERVER_PORT", _uri.Port.ToString(CultureInfo.InvariantCulture) },
|
||||||
{ "HTTP_HOST", _uri.Authority.ToString(CultureInfo.InvariantCulture) },
|
{ "HTTP_HOST", _uri.Authority.ToString(CultureInfo.InvariantCulture) },
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -265,16 +245,6 @@ namespace Orchard.Mvc {
|
|||||||
return new HttpBrowserCapabilitiesPlaceholder();
|
return new HttpBrowserCapabilitiesPlaceholder();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override RequestContext RequestContext {
|
|
||||||
get {
|
|
||||||
if (_requestContext == null) {
|
|
||||||
_requestContext = new RequestContext(_httpContext, new RouteData());
|
|
||||||
}
|
|
||||||
return _requestContext;
|
|
||||||
}
|
|
||||||
set { _requestContext = value; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HttpBrowserCapabilitiesPlaceholder : HttpBrowserCapabilitiesBase {
|
public class HttpBrowserCapabilitiesPlaceholder : HttpBrowserCapabilitiesBase {
|
||||||
|
@@ -149,12 +149,11 @@
|
|||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="BackgroundHttpContextFactory.cs" />
|
||||||
<Compile Include="Localization\Services\ILocalizationStreamParser.cs" />
|
<Compile Include="Localization\Services\ILocalizationStreamParser.cs" />
|
||||||
<Compile Include="Localization\Services\LocalizationStreamParser.cs" />
|
<Compile Include="Localization\Services\LocalizationStreamParser.cs" />
|
||||||
<Compile Include="Security\ISslSettingsProvider.cs" />
|
<Compile Include="Security\ISslSettingsProvider.cs" />
|
||||||
<Compile Include="Security\Providers\DefaultSslSettingsProvider.cs" />
|
<Compile Include="Security\Providers\DefaultSslSettingsProvider.cs" />
|
||||||
<Compile Include="StaticHttpContextScope.cs" />
|
|
||||||
<Compile Include="StaticHttpContextScopeFactory.cs" />
|
|
||||||
<Compile Include="Caching\DefaultCacheContextAccessor.cs" />
|
<Compile Include="Caching\DefaultCacheContextAccessor.cs" />
|
||||||
<Compile Include="Caching\DefaultParallelCacheContext.cs" />
|
<Compile Include="Caching\DefaultParallelCacheContext.cs" />
|
||||||
<Compile Include="Caching\ICacheContextAccessor.cs" />
|
<Compile Include="Caching\ICacheContextAccessor.cs" />
|
||||||
@@ -323,7 +322,7 @@
|
|||||||
<Compile Include="Mvc\DataAnnotations\LocalizedModelValidatorProvider.cs" />
|
<Compile Include="Mvc\DataAnnotations\LocalizedModelValidatorProvider.cs" />
|
||||||
<Compile Include="Mvc\DataAnnotations\LocalizedRequiredAttribute.cs" />
|
<Compile Include="Mvc\DataAnnotations\LocalizedRequiredAttribute.cs" />
|
||||||
<Compile Include="Mvc\Extensions\RouteExtension.cs" />
|
<Compile Include="Mvc\Extensions\RouteExtension.cs" />
|
||||||
<Compile Include="Mvc\Extensions\HttpContextExtensions.cs" />
|
<Compile Include="Mvc\Extensions\HttpContextBaseExtensions.cs" />
|
||||||
<Compile Include="Mvc\FormValueRequiredAttribute.cs" />
|
<Compile Include="Mvc\FormValueRequiredAttribute.cs" />
|
||||||
<Compile Include="Mvc\HttpContextAccessor.cs" />
|
<Compile Include="Mvc\HttpContextAccessor.cs" />
|
||||||
<Compile Include="Mvc\HttpContextWorkContext.cs" />
|
<Compile Include="Mvc\HttpContextWorkContext.cs" />
|
||||||
@@ -653,7 +652,7 @@
|
|||||||
<Compile Include="WebApi\Filters\OrchardApiActionFilterDispatcher.cs" />
|
<Compile Include="WebApi\Filters\OrchardApiActionFilterDispatcher.cs" />
|
||||||
<Compile Include="WebApi\Routes\IHttpRouteProvider.cs" />
|
<Compile Include="WebApi\Routes\IHttpRouteProvider.cs" />
|
||||||
<Compile Include="WebApi\Routes\StandardExtensionHttpRouteProvider.cs" />
|
<Compile Include="WebApi\Routes\StandardExtensionHttpRouteProvider.cs" />
|
||||||
<Compile Include="IStaticHttpContextScopeFactory.cs" />
|
<Compile Include="IBackgroundHttpContextFactory.cs" />
|
||||||
<Compile Include="WorkContextExtensions.cs" />
|
<Compile Include="WorkContextExtensions.cs" />
|
||||||
<Compile Include="Mvc\ViewEngines\Razor\RazorCompilationEventsShim.cs" />
|
<Compile Include="Mvc\ViewEngines\Razor\RazorCompilationEventsShim.cs" />
|
||||||
<Compile Include="Mvc\ViewEngines\Razor\RazorViewEngineProvider.cs" />
|
<Compile Include="Mvc\ViewEngines\Razor\RazorViewEngineProvider.cs" />
|
||||||
@@ -1029,4 +1028,4 @@
|
|||||||
<Target Name="AfterBuild">
|
<Target Name="AfterBuild">
|
||||||
</Target>
|
</Target>
|
||||||
-->
|
-->
|
||||||
</Project>
|
</Project>
|
@@ -1,17 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Web;
|
|
||||||
|
|
||||||
namespace Orchard {
|
|
||||||
public class StaticHttpContextScope : IDisposable {
|
|
||||||
private readonly HttpContext _previousHttpContext;
|
|
||||||
|
|
||||||
public StaticHttpContextScope(HttpContext stub) {
|
|
||||||
_previousHttpContext = HttpContext.Current;
|
|
||||||
HttpContext.Current = stub;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose() {
|
|
||||||
HttpContext.Current = _previousHttpContext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,31 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Web;
|
|
||||||
using Orchard.Settings;
|
|
||||||
|
|
||||||
namespace Orchard {
|
|
||||||
public class StaticHttpContextScopeFactory : IStaticHttpContextScopeFactory {
|
|
||||||
private readonly Func<ISiteService> _siteService;
|
|
||||||
public StaticHttpContextScopeFactory(Func<ISiteService> siteService) {
|
|
||||||
_siteService = siteService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public const string IsBackgroundHttpContextKey = "IsBackgroundHttpContext";
|
|
||||||
|
|
||||||
public IDisposable CreateStaticScope() {
|
|
||||||
// If there already is a current HttpContext, use that one as the stub.
|
|
||||||
if(HttpContext.Current != null)
|
|
||||||
return new StaticHttpContextScope(HttpContext.Current);
|
|
||||||
|
|
||||||
// We're in a background task (or some other static context like the console),
|
|
||||||
// so create a stub context so that Html Helpers can still be executed when rendering shapes in background tasks
|
|
||||||
// (sadly enought some Html Helpers access HttpContext.Current directly).
|
|
||||||
var url = _siteService().GetSiteSettings().BaseUrl;
|
|
||||||
var stub = new HttpContext(new HttpRequest("", url, ""), new HttpResponse(new StringWriter()));
|
|
||||||
|
|
||||||
stub.Items[IsBackgroundHttpContextKey] = true;
|
|
||||||
|
|
||||||
return new StaticHttpContextScope(stub);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -18,7 +18,8 @@ namespace Orchard.Tasks {
|
|||||||
public BackgroundService(
|
public BackgroundService(
|
||||||
IEnumerable<IBackgroundTask> tasks,
|
IEnumerable<IBackgroundTask> tasks,
|
||||||
ITransactionManager transactionManager,
|
ITransactionManager transactionManager,
|
||||||
ShellSettings shellSettings) {
|
ShellSettings shellSettings,
|
||||||
|
IBackgroundHttpContextFactory backgroundHttpContextFactory) {
|
||||||
|
|
||||||
_tasks = tasks;
|
_tasks = tasks;
|
||||||
_transactionManager = transactionManager;
|
_transactionManager = transactionManager;
|
||||||
|
@@ -41,7 +41,7 @@ namespace Orchard.Tasks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Elapsed(object sender, ElapsedEventArgs e) {
|
void Elapsed(object sender, ElapsedEventArgs e) {
|
||||||
// Current implementation disallows re-entrancy.
|
// current implementation disallows re-entrancy
|
||||||
if (!System.Threading.Monitor.TryEnter(_timer))
|
if (!System.Threading.Monitor.TryEnter(_timer))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ namespace Orchard.Tasks {
|
|||||||
|
|
||||||
public void DoWork() {
|
public void DoWork() {
|
||||||
using (var scope = _workContextAccessor.CreateWorkContextScope()) {
|
using (var scope = _workContextAccessor.CreateWorkContextScope()) {
|
||||||
// Resolve the manager and invoke it.
|
// resolve the manager and invoke it
|
||||||
var manager = scope.Resolve<IBackgroundService>();
|
var manager = scope.Resolve<IBackgroundService>();
|
||||||
manager.Sweep();
|
manager.Sweep();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user