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:
Sebastien Ros
2015-09-04 10:59:31 -07:00
parent e118695ea7
commit 04f29ba70c
23 changed files with 76 additions and 209 deletions

View File

@@ -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]

View File

@@ -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>();

View File

@@ -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]

View File

@@ -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;
} }

View File

@@ -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());
} }

View File

@@ -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

View File

@@ -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);
} }

View File

@@ -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();
} }

View File

@@ -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;

View File

@@ -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());

View File

@@ -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();

View File

@@ -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();
}; };
} }

View File

@@ -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();
}
}

View 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;
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
} }
} }
} }

View File

@@ -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);
} }
} }

View File

@@ -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 {

View File

@@ -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>

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;

View File

@@ -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();
} }