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>()
.Setup(x => x.Current())
.Returns(() => _httpContextCurrent);
container.Mock<IHttpContextAccessor>()
.Setup(x => x.CreateContext(It.IsAny<ILifetimeScope>()))
.Returns(() => new StubHttpContext());
container.Mock<IWorkContextEvents>()
.Setup(x => x.Started());
}
[Test]

View File

@@ -56,11 +56,7 @@ namespace Orchard.Tests.Environment.ShellBuilders {
_container.Mock<IHttpContextAccessor>()
.Setup(x => x.Current())
.Returns(httpContext);
_container.Mock<IHttpContextAccessor>()
.Setup(x => x.CreateContext(It.IsAny<ILifetimeScope>()))
.Returns(httpContext);
.Returns(default(HttpContextBase));
var factory = _container.Resolve<IShellContextFactory>();

View File

@@ -43,10 +43,6 @@ namespace Orchard.Tests.Environment.State {
_container.Mock<IHttpContextAccessor>()
.Setup(x=>x.Current())
.Returns(httpContext);
_container.Mock<IHttpContextAccessor>()
.Setup(x => x.CreateContext(It.IsAny<ILifetimeScope>()))
.Returns(httpContext);
}
[TearDown]

View File

@@ -1,5 +1,4 @@
using System.Web;
using Autofac;
using Orchard.Mvc;
namespace Orchard.Tests.Stubs {
@@ -17,10 +16,6 @@ namespace Orchard.Tests.Stubs {
return _httpContext;
}
public HttpContextBase CreateContext(ILifetimeScope lifetimeScope) {
return _httpContext;
}
public void Set(HttpContextBase httpContext) {
_httpContext = httpContext;
}

View File

@@ -23,10 +23,6 @@ namespace Orchard.Tests.Tasks {
.Setup(x => x.Current())
.Returns(() => null);
container.Mock<IHttpContextAccessor>()
.Setup(x => x.CreateContext(It.IsAny<ILifetimeScope>()))
.Returns(() => new StubHttpContext());
container.Mock<IWorkContextEvents>()
.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.Data.Migration;
namespace Orchard.Autoroute {
public class Migrations : DataMigrationImpl {
public int Create() {
SchemaBuilder.CreateTable("AutoroutePartRecord",
table => table

View File

@@ -16,7 +16,6 @@ namespace Orchard.Layouts.Handlers {
private readonly IContentPartDisplay _contentPartDisplay;
private readonly IShapeDisplay _shapeDisplay;
private readonly ILayoutSerializer _serializer;
private readonly IStaticHttpContextScopeFactory _staticHttpContextScopeFactory;
private readonly IAliasService _aliasService;
public LayoutPartHandler(
@@ -26,7 +25,6 @@ namespace Orchard.Layouts.Handlers {
IContentPartDisplay contentPartDisplay,
IShapeDisplay shapeDisplay,
ILayoutSerializer serializer,
IStaticHttpContextScopeFactory staticHttpContextScopeFactory,
IAliasService aliasService) {
_layoutManager = layoutManager;
@@ -34,7 +32,6 @@ namespace Orchard.Layouts.Handlers {
_contentPartDisplay = contentPartDisplay;
_shapeDisplay = shapeDisplay;
_serializer = serializer;
_staticHttpContextScopeFactory = staticHttpContextScopeFactory;
_aliasService = aliasService;
Filters.Add(StorageFilter.For(repository));
@@ -44,22 +41,13 @@ namespace Orchard.Layouts.Handlers {
private void IndexLayout(IndexContentContext context, LayoutPart part) {
var layoutShape = _contentPartDisplay.BuildDisplay(part);
var layoutHtml = RenderShape(layoutShape);
var layoutHtml = _shapeDisplay.Display(layoutShape);
context.DocumentIndex
.Add("body", layoutHtml).RemoveTags().Analyze()
.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) {
UpdateTemplateClients(part);
}

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.UI;
using System.Web.WebPages;
@@ -14,6 +15,7 @@ namespace Orchard.Templates.Services {
[OrchardFeature("Orchard.Templates.Razor")]
public class RazorTemplateProcessor : TemplateProcessorImpl {
private readonly IRazorCompiler _compiler;
private readonly HttpContextBase _httpContextBase;
private readonly IWorkContextAccessor _wca;
public override string Type {
@@ -22,9 +24,11 @@ namespace Orchard.Templates.Services {
public RazorTemplateProcessor(
IRazorCompiler compiler,
HttpContextBase httpContextBase,
IWorkContextAccessor wca) {
_compiler = compiler;
_httpContextBase = httpContextBase;
_wca = wca;
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) {
if (String.IsNullOrEmpty(template))
return String.Empty;
return string.Empty;
var compiledTemplate = _compiler.CompileRazor(template, name, new Dictionary<string, object>());
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,
// for instance: <a href="@WorkContext.CurrentSite.BaseUrl">Homepage</a>.
var viewData = new ViewDataDictionary(model);
var httpContext = _wca.GetContext().HttpContext;
obj.ViewContext = new ViewContext(
new ControllerContext(
httpContext.Request.RequestContext,
_httpContextBase.Request.RequestContext,
new StubController()),
new StubView(),
viewData,
@@ -80,7 +83,7 @@ namespace Orchard.Templates.Services {
htmlWriter);
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();
}

View File

@@ -179,8 +179,8 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy {
private ControllerContext CreateControllerContext() {
var controller = new StubController();
var httpContext = _workContextAccessor.GetContext().HttpContext;
var requestContext = httpContext.Request.RequestContext;
var httpContext = _workContextAccessor.GetContext().Resolve<HttpContextBase>();
var requestContext = _workContextAccessor.GetContext().Resolve<RequestContext>();
var routeData = requestContext.RouteData;
routeData.DataTokens["IWorkContextAccessor"] = _workContextAccessor;

View File

@@ -1,6 +1,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Orchard.DisplayManagement.Implementation;
using Orchard.DisplayManagement.Shapes;
@@ -8,24 +10,28 @@ namespace Orchard.DisplayManagement {
public class ShapeDisplay : IShapeDisplay {
private readonly IDisplayHelperFactory _displayHelperFactory;
private readonly IWorkContextAccessor _workContextAccessor;
private readonly HttpContextBase _httpContextBase;
private readonly RequestContext _requestContext;
public ShapeDisplay(
IDisplayHelperFactory displayHelperFactory,
IWorkContextAccessor workContextAccessor) {
IDisplayHelperFactory displayHelperFactory,
IWorkContextAccessor workContextAccessor,
HttpContextBase httpContextBase,
RequestContext requestContext) {
_displayHelperFactory = displayHelperFactory;
_workContextAccessor = workContextAccessor;
_httpContextBase = httpContextBase;
_requestContext = requestContext;
}
public string Display(Shape shape) {
return Display((object)shape);
return Display((object) shape);
}
public string Display(object shape) {
var workContext = _workContextAccessor.GetContext();
var httpContext = workContext.HttpContext;
var viewContext = new ViewContext {
HttpContext = httpContext,
RequestContext = httpContext.Request.RequestContext
HttpContext = _httpContextBase,
RequestContext = _requestContext
};
viewContext.RouteData.DataTokens["IWorkContextAccessor"] = _workContextAccessor;
var display = _displayHelperFactory.CreateHelper(viewContext, new ViewDataContainer());

View File

@@ -63,7 +63,7 @@ namespace Orchard.Environment {
builder.RegisterType<AppDomainAssemblyNameResolver>().As<IAssemblyNameResolver>().SingleInstance();
builder.RegisterType<GacAssemblyNameResolver>().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<DefaultExceptionPolicy>().As<IExceptionPolicy>().SingleInstance();
builder.RegisterType<DefaultCriticalErrorProvider>().As<ICriticalErrorProvider>().SingleInstance();

View File

@@ -60,14 +60,11 @@ namespace Orchard.Environment {
return CreateWorkContextScope(httpContext);
var workLifetime = _lifetimeScope.BeginLifetimeScope("work");
httpContext = _httpContextAccessor.CreateContext(workLifetime);
workLifetime.Resolve<WorkContextProperty<HttpContextBase>>().Value = httpContext;
var events = workLifetime.Resolve<IEnumerable<IWorkContextEvents>>();
events.Invoke(e => e.Started(), NullLogger.Instance);
return new ThreadStaticScopeImplementation(
httpContext,
events,
workLifetime,
EnsureThreadStaticContexts(),
@@ -116,9 +113,8 @@ namespace Orchard.Environment {
readonly WorkContext _workContext;
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>();
httpContext.Items[workContextKey] = _workContext;
contexts.AddOrUpdate(workContextKey, _workContext, (a, b) => _workContext);
_disposer = () => {
@@ -127,11 +123,6 @@ namespace Orchard.Environment {
WorkContext removedContext;
contexts.TryRemove(workContextKey, out removedContext);
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.Collections.Concurrent;
using System.Web;
using Autofac;
using Orchard.Mvc.Extensions;
using Orchard.Settings;
namespace Orchard.Mvc {
public class HttpContextAccessor : IHttpContextAccessor {
readonly object _contextKey = new object();
[ThreadStatic]
static ConcurrentDictionary<object, HttpContextBase> _threadStaticContexts;
private HttpContextBase _httpContext;
public HttpContextBase Current() {
if (!HttpContext.Current.IsBackgroundContext())
return new HttpContextWrapper(HttpContext.Current);
return GetContext();
var httpContext = GetStaticProperty();
return !IsBackgroundHttpContext(httpContext) ? new HttpContextWrapper(httpContext) : _httpContext;
}
public HttpContextBase CreateContext(ILifetimeScope lifetimeScope) {
return new MvcModule.HttpContextPlaceholder(_threadStaticContexts, _contextKey, () => {
var baseUrl = lifetimeScope.Resolve<ISiteService>().GetSiteSettings().BaseUrl;
return !String.IsNullOrEmpty(baseUrl) ? baseUrl : "http://localhost"; // Return a valid URL always.
});
public void Set(HttpContextBase httpContext) {
_httpContext = httpContext;
}
private HttpContextBase GetContext() {
HttpContextBase context;
return ThreadStaticContexts.TryGetValue(_contextKey, out context) ? context : null;
private static bool IsBackgroundHttpContext(HttpContext httpContext) {
return httpContext == null || httpContext.Items.Contains(BackgroundHttpContextFactory.IsBackgroundHttpContextKey);
}
static ConcurrentDictionary<object, HttpContextBase> ThreadStaticContexts {
get {
return _threadStaticContexts ?? (_threadStaticContexts = new ConcurrentDictionary<object, HttpContextBase>());
private static HttpContext GetStaticProperty() {
var httpContext = HttpContext.Current;
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 Autofac;
namespace Orchard.Mvc {
public interface IHttpContextAccessor {
HttpContextBase Current();
HttpContextBase CreateContext(ILifetimeScope lifetimeScope);
void Set(HttpContextBase httpContext);
}
}

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
@@ -10,7 +9,6 @@ using System.Web.Instrumentation;
using System.Web.Mvc;
using System.Web.Routing;
using Autofac;
using Orchard.Mvc.Extensions;
using Orchard.Mvc.Routes;
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,
// thus preventing a StackOverflowException.
var baseUrl = new Func<string>(() => siteService.GetSiteSettings().BaseUrl);
var httpContextBase = context.Resolve<IHttpContextAccessor>().Current();
var httpContextBase = new HttpContextPlaceholder(baseUrl);
if (httpContextBase == null) {
context.Resolve<IWorkContextAccessor>().CreateWorkContextScope();
@@ -66,7 +64,7 @@ namespace Orchard.Mvc {
static RequestContext RequestContextFactory(IComponentContext context) {
var httpContextAccessor = context.Resolve<IHttpContextAccessor>();
var httpContext = httpContextAccessor.Current();
if (!httpContext.IsBackgroundContext()) {
if (httpContext != null) {
var mvcHandler = httpContext.Handler as MvcHandler;
if (mvcHandler != null) {
@@ -93,23 +91,16 @@ namespace Orchard.Mvc {
/// <summary>
/// Standin context for background tasks.
/// </summary>
public class HttpContextPlaceholder : HttpContextBase, IDisposable {
public class HttpContextPlaceholder : HttpContextBase {
private readonly Lazy<string> _baseUrl;
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);
contexts.AddOrUpdate(contextKey, this, (a, b) => this);
_disposer = () => {
HttpContextBase removedContext;
contexts.TryRemove(contextKey, out removedContext);
};
}
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; }
@@ -118,10 +109,6 @@ namespace Orchard.Mvc {
get { return new HttpResponsePlaceholder(); }
}
public override HttpSessionStateBase Session {
get { return null; }
}
public override IDictionary Items {
get { return _items; }
}
@@ -137,10 +124,6 @@ namespace Orchard.Mvc {
public override object GetService(Type serviceType) {
return null;
}
public void Dispose() {
_disposer();
}
}
public class HttpResponsePlaceholder : HttpResponseBase {
@@ -159,12 +142,9 @@ namespace Orchard.Mvc {
/// standin context for background tasks.
/// </summary>
public class HttpRequestPlaceholder : HttpRequestBase {
private readonly HttpContextBase _httpContext;
private readonly Uri _uri;
private RequestContext _requestContext;
public HttpRequestPlaceholder(HttpContextBase httpContext, Uri uri) {
_httpContext = httpContext;
public HttpRequestPlaceholder(Uri uri) {
_uri = uri;
}
@@ -223,7 +203,7 @@ namespace Orchard.Mvc {
return new NameValueCollection {
{ "SERVER_PORT", _uri.Port.ToString(CultureInfo.InvariantCulture) },
{ "HTTP_HOST", _uri.Authority.ToString(CultureInfo.InvariantCulture) },
};
}
}
@@ -265,16 +245,6 @@ namespace Orchard.Mvc {
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 {

View File

@@ -149,12 +149,11 @@
<Reference Include="System.Xml.Linq" />
</ItemGroup>
<ItemGroup>
<Compile Include="BackgroundHttpContextFactory.cs" />
<Compile Include="Localization\Services\ILocalizationStreamParser.cs" />
<Compile Include="Localization\Services\LocalizationStreamParser.cs" />
<Compile Include="Security\ISslSettingsProvider.cs" />
<Compile Include="Security\Providers\DefaultSslSettingsProvider.cs" />
<Compile Include="StaticHttpContextScope.cs" />
<Compile Include="StaticHttpContextScopeFactory.cs" />
<Compile Include="Caching\DefaultCacheContextAccessor.cs" />
<Compile Include="Caching\DefaultParallelCacheContext.cs" />
<Compile Include="Caching\ICacheContextAccessor.cs" />
@@ -323,7 +322,7 @@
<Compile Include="Mvc\DataAnnotations\LocalizedModelValidatorProvider.cs" />
<Compile Include="Mvc\DataAnnotations\LocalizedRequiredAttribute.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\HttpContextAccessor.cs" />
<Compile Include="Mvc\HttpContextWorkContext.cs" />
@@ -653,7 +652,7 @@
<Compile Include="WebApi\Filters\OrchardApiActionFilterDispatcher.cs" />
<Compile Include="WebApi\Routes\IHttpRouteProvider.cs" />
<Compile Include="WebApi\Routes\StandardExtensionHttpRouteProvider.cs" />
<Compile Include="IStaticHttpContextScopeFactory.cs" />
<Compile Include="IBackgroundHttpContextFactory.cs" />
<Compile Include="WorkContextExtensions.cs" />
<Compile Include="Mvc\ViewEngines\Razor\RazorCompilationEventsShim.cs" />
<Compile Include="Mvc\ViewEngines\Razor\RazorViewEngineProvider.cs" />
@@ -1029,4 +1028,4 @@
<Target Name="AfterBuild">
</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(
IEnumerable<IBackgroundTask> tasks,
ITransactionManager transactionManager,
ShellSettings shellSettings) {
ShellSettings shellSettings,
IBackgroundHttpContextFactory backgroundHttpContextFactory) {
_tasks = tasks;
_transactionManager = transactionManager;

View File

@@ -41,7 +41,7 @@ namespace Orchard.Tasks {
}
void Elapsed(object sender, ElapsedEventArgs e) {
// Current implementation disallows re-entrancy.
// current implementation disallows re-entrancy
if (!System.Threading.Monitor.TryEnter(_timer))
return;
@@ -60,7 +60,7 @@ namespace Orchard.Tasks {
public void DoWork() {
using (var scope = _workContextAccessor.CreateWorkContextScope()) {
// Resolve the manager and invoke it.
// resolve the manager and invoke it
var manager = scope.Resolve<IBackgroundService>();
manager.Sweep();
}