Introduce IUmbracoContextFactory

This commit is contained in:
Stephan
2019-02-14 12:11:06 +01:00
parent e5142e4915
commit 186e8fc58b
20 changed files with 285 additions and 249 deletions

View File

@@ -5,11 +5,14 @@ using Moq;
using NUnit.Framework;
using Umbraco.Core.Components;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
using Umbraco.Tests.Testing;
using Umbraco.Tests.Testing.Objects.Accessors;
using Umbraco.Web;
using Umbraco.Web.Cache;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.Routing;
@@ -149,8 +152,18 @@ namespace Umbraco.Tests.Cache
};
var umbracoContextFactory = new UmbracoContextFactory(
new TestUmbracoContextAccessor(),
Mock.Of<IPublishedSnapshotService>(),
new TestVariationContextAccessor(),
new TestDefaultCultureAccessor(),
TestObjects.GetUmbracoSettings(),
TestObjects.GetGlobalSettings(),
Enumerable.Empty<IUrlProvider>(),
Mock.Of<IUserService>());
// just assert it does not throw
var refreshers = new DistributedCacheBinder(null, null);
var refreshers = new DistributedCacheBinder(null, umbracoContextFactory, null);
refreshers.HandleEvents(definitions);
}
}

View File

@@ -473,7 +473,7 @@ namespace Umbraco.Tests.IO
scope.Dispose();
scopedFileSystems = false;
Assert.IsTrue(phy.FileExists("sub/f5.txt"));
Assert.IsFalse(Directory.Exists(shadowfs + "/" + id));
TestHelper.TryAssert(() => Assert.IsFalse(Directory.Exists(shadowfs + "/" + id)));
}
[Test]

View File

@@ -13,6 +13,7 @@ using Umbraco.Core.Sync;
using Umbraco.Tests.Services;
using Umbraco.Tests.TestHelpers.Entities;
using Umbraco.Tests.Testing;
using Umbraco.Web;
using Umbraco.Web.Cache;
using static Umbraco.Tests.Cache.DistributedCache.DistributedCacheTests;
@@ -32,7 +33,7 @@ namespace Umbraco.Tests.Integration
{
base.SetUp();
_h1 = new DistributedCacheBinder(new DistributedCache(), Mock.Of<ILogger>());
_h1 = new DistributedCacheBinder(new DistributedCache(), Mock.Of<IUmbracoContextFactory>(), Mock.Of<ILogger>());
_h1.BindEvents(true);
_events = new List<EventInstance>();

View File

@@ -45,7 +45,8 @@ namespace Umbraco.Tests.Routing
runtime,
logger,
null, // FIXME: PublishedRouter complexities...
Mock.Of<IVariationContextAccessor>()
Mock.Of<IVariationContextAccessor>(),
Mock.Of<IUmbracoContextFactory>()
);
runtime.Level = RuntimeLevel.Run;

View File

@@ -101,6 +101,7 @@ namespace Umbraco.Tests.Runtimes
composition.WithCollectionBuilder<UrlProviderCollectionBuilder>().Append<DefaultUrlProvider>();
composition.RegisterUnique<IDistributedCacheBinder, DistributedCacheBinder>();
composition.RegisterUnique<IExamineManager>(f => ExamineManager.Instance);
composition.RegisterUnique<IUmbracoContextFactory, UmbracoContextFactory>();
// initialize some components only/individually
composition.WithCollectionBuilder<ComponentCollectionBuilder>()
@@ -179,8 +180,9 @@ namespace Umbraco.Tests.Runtimes
// need an UmbracoCOntext to access the cache
// FIXME: not exactly pretty, should not depend on HttpContext
var httpContext = Mock.Of<HttpContextBase>();
var withUmbracoContext = UmbracoContext.EnsureContext(httpContext);
var umbracoContext = Umbraco.Web.Composing.Current.UmbracoContext;
var umbracoContextFactory = factory.GetInstance<IUmbracoContextFactory>();
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(httpContext);
var umbracoContext = umbracoContextReference.UmbracoContext;
// assert that there is no published document
var pcontent = umbracoContext.ContentCache.GetById(content.Id);
@@ -218,7 +220,7 @@ namespace Umbraco.Tests.Runtimes
// and the published document has a url
Assert.AreEqual("/test/", pcontent.GetUrl());
withUmbracoContext.Dispose();
umbracoContextReference.Dispose();
mainDom.Stop();
components.Terminate();

View File

@@ -131,7 +131,7 @@ namespace Umbraco.Tests.Scoping
var umbracoContext = GetUmbracoContextNu("http://example.com/", setSingleton: true);
// wire cache refresher
_distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(), Mock.Of<ILogger>());
_distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(), Mock.Of<IUmbracoContextFactory>(), Mock.Of<ILogger>());
_distributedCacheBinder.BindEvents(true);
// create document type, document

View File

@@ -14,6 +14,7 @@ using Moq;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Sync;
using Umbraco.Web;
namespace Umbraco.Tests.Scoping
{
@@ -73,7 +74,7 @@ namespace Umbraco.Tests.Scoping
// get user again - else we'd modify the one that's in the cache
user = service.GetUserById(user.Id);
_distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(), Mock.Of<ILogger>());
_distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(), Mock.Of<IUmbracoContextFactory>(), Mock.Of<ILogger>());
_distributedCacheBinder.BindEvents(true);
Assert.IsNull(scopeProvider.AmbientScope);
@@ -154,7 +155,7 @@ namespace Umbraco.Tests.Scoping
Assert.AreEqual(lang.Id, globalCached.Id);
Assert.AreEqual("fr-FR", globalCached.IsoCode);
_distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(), Mock.Of<ILogger>());
_distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(), Mock.Of<IUmbracoContextFactory>(), Mock.Of<ILogger>());
_distributedCacheBinder.BindEvents(true);
Assert.IsNull(scopeProvider.AmbientScope);
@@ -246,7 +247,7 @@ namespace Umbraco.Tests.Scoping
Assert.AreEqual(item.Id, globalCached.Id);
Assert.AreEqual("item-key", globalCached.ItemKey);
_distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(), Mock.Of<ILogger>());
_distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(), Mock.Of<IUmbracoContextFactory>(), Mock.Of<ILogger>());
_distributedCacheBinder.BindEvents(true);
Assert.IsNull(scopeProvider.AmbientScope);

View File

@@ -15,6 +15,7 @@ using Umbraco.Core.Sync;
using Umbraco.Tests.LegacyXmlPublishedCache;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.Testing;
using Umbraco.Web;
using Umbraco.Web.Cache;
using Umbraco.Web.PublishedCache;
@@ -91,7 +92,7 @@ namespace Umbraco.Tests.Scoping
var item = new Content("name", -1, contentType);
// wire cache refresher
_distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(), Mock.Of<ILogger>());
_distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(), Mock.Of<IUmbracoContextFactory>(), Mock.Of<ILogger>());
_distributedCacheBinder.BindEvents(true);
// check xml in context = "before"
@@ -204,7 +205,7 @@ namespace Umbraco.Tests.Scoping
Current.Services.ContentTypeService.Save(contentType);
// wire cache refresher
_distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(), Mock.Of<ILogger>());
_distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(), Mock.Of<IUmbracoContextFactory>(), Mock.Of<ILogger>());
_distributedCacheBinder.BindEvents(true);
// check xml in context = "before"

View File

@@ -135,16 +135,17 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
var umbracoContextAccessor = Umbraco.Web.Composing.Current.UmbracoContextAccessor;
var umbCtx = UmbracoContext.EnsureContext(
var umbracoContextFactory = new UmbracoContextFactory(
umbracoContextAccessor,
httpContext,
publishedSnapshotService.Object,
webSecurity.Object,
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == UrlProviderMode.Auto.ToString())),
Enumerable.Empty<IUrlProvider>(),
globalSettings,
new TestVariationContextAccessor(),
true); //replace it
new TestDefaultCultureAccessor(),
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == "Auto")),
globalSettings,
Enumerable.Empty<IUrlProvider>(),
Mock.Of<IUserService>());
var umbCtx = umbracoContextFactory.EnsureUmbracoContext(httpContext).UmbracoContext;
var urlHelper = new Mock<IUrlProvider>();
urlHelper.Setup(provider => provider.GetUrl(It.IsAny<UmbracoContext>(), It.IsAny<IPublishedContent>(), It.IsAny<UrlProviderMode>(), It.IsAny<string>(), It.IsAny<Uri>()))

View File

@@ -116,11 +116,21 @@ namespace Umbraco.Tests.TestHelpers
var umbracoSettings = GetUmbracoSettings();
var globalSettings = GetGlobalSettings();
var webSecurity = new Mock<WebSecurity>(null, null, globalSettings).Object;
var urlProviders = Enumerable.Empty<IUrlProvider>();
if (accessor == null) accessor = new TestUmbracoContextAccessor();
return UmbracoContext.EnsureContext(accessor, httpContext, publishedSnapshotService, webSecurity, umbracoSettings, urlProviders, globalSettings, new TestVariationContextAccessor(), true);
var umbracoContextFactory = new UmbracoContextFactory(
accessor,
publishedSnapshotService,
new TestVariationContextAccessor(),
new TestDefaultCultureAccessor(),
umbracoSettings,
globalSettings,
urlProviders,
Mock.Of<IUserService>());
return umbracoContextFactory.EnsureUmbracoContext(httpContext).UmbracoContext;
}
public IUmbracoSettingsSection GetUmbracoSettings()
@@ -143,7 +153,7 @@ namespace Umbraco.Tests.TestHelpers
public IFileSystems GetFileSystemsMock()
{
var fileSystems = Mock.Of<IFileSystems>();
MockFs(fileSystems, x => x.MacroPartialsFileSystem);
MockFs(fileSystems, x => x.MvcViewsFileSystem);
MockFs(fileSystems, x => x.PartialViewsFileSystem);

View File

@@ -63,19 +63,20 @@ namespace Umbraco.Tests.Web.Mvc
var globalSettings = TestObjects.GetGlobalSettings();
var attr = new RenderIndexActionSelectorAttribute();
var req = new RequestContext();
//var appCtx = new ApplicationContext(
// CacheHelper.CreateDisabledCacheHelper(),
// new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>()));
var umbCtx = UmbracoContext.EnsureContext(
var umbracoContextFactory = new UmbracoContextFactory(
Current.UmbracoContextAccessor,
Mock.Of<HttpContextBase>(),
Mock.Of<IPublishedSnapshotService>(),
new Mock<WebSecurity>(null, null, globalSettings).Object,
TestObjects.GetUmbracoSettings(),
Enumerable.Empty<IUrlProvider>(),
globalSettings,
new TestVariationContextAccessor(),
true);
new TestDefaultCultureAccessor(),
TestObjects.GetUmbracoSettings(),
globalSettings,
Enumerable.Empty<IUrlProvider>(),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
var umbCtx = umbracoContextReference.UmbracoContext;
var ctrl = new MatchesDefaultIndexController { UmbracoContext = umbCtx };
var controllerCtx = new ControllerContext(req, ctrl);
var result = attr.IsValidForRequest(controllerCtx,
@@ -90,16 +91,20 @@ namespace Umbraco.Tests.Web.Mvc
var globalSettings = TestObjects.GetGlobalSettings();
var attr = new RenderIndexActionSelectorAttribute();
var req = new RequestContext();
var umbCtx = UmbracoContext.EnsureContext(
var umbracoContextFactory = new UmbracoContextFactory(
Current.UmbracoContextAccessor,
Mock.Of<HttpContextBase>(),
Mock.Of<IPublishedSnapshotService>(),
new Mock<WebSecurity>(null, null, globalSettings).Object,
TestObjects.GetUmbracoSettings(),
Enumerable.Empty<IUrlProvider>(),
globalSettings,
new TestVariationContextAccessor(),
true);
new TestDefaultCultureAccessor(),
TestObjects.GetUmbracoSettings(),
globalSettings,
Enumerable.Empty<IUrlProvider>(),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
var umbCtx = umbracoContextReference.UmbracoContext;
var ctrl = new MatchesOverriddenIndexController { UmbracoContext = umbCtx };
var controllerCtx = new ControllerContext(req, ctrl);
var result = attr.IsValidForRequest(controllerCtx,
@@ -114,16 +119,20 @@ namespace Umbraco.Tests.Web.Mvc
var globalSettings = TestObjects.GetGlobalSettings();
var attr = new RenderIndexActionSelectorAttribute();
var req = new RequestContext();
var umbCtx = UmbracoContext.EnsureContext(
var umbracoContextFactory = new UmbracoContextFactory(
Current.UmbracoContextAccessor,
Mock.Of<HttpContextBase>(),
Mock.Of<IPublishedSnapshotService>(),
new Mock<WebSecurity>(null, null, globalSettings).Object,
TestObjects.GetUmbracoSettings(),
Enumerable.Empty<IUrlProvider>(),
globalSettings,
new TestVariationContextAccessor(),
true);
new TestDefaultCultureAccessor(),
TestObjects.GetUmbracoSettings(),
globalSettings,
Enumerable.Empty<IUrlProvider>(),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
var umbCtx = umbracoContextReference.UmbracoContext;
var ctrl = new MatchesCustomIndexController { UmbracoContext = umbCtx };
var controllerCtx = new ControllerContext(req, ctrl);
var result = attr.IsValidForRequest(controllerCtx,
@@ -138,16 +147,20 @@ namespace Umbraco.Tests.Web.Mvc
var globalSettings = TestObjects.GetGlobalSettings();
var attr = new RenderIndexActionSelectorAttribute();
var req = new RequestContext();
var umbCtx = UmbracoContext.EnsureContext(
var umbracoContextFactory = new UmbracoContextFactory(
Current.UmbracoContextAccessor,
Mock.Of<HttpContextBase>(),
Mock.Of<IPublishedSnapshotService>(),
new Mock<WebSecurity>(null, null, globalSettings).Object,
TestObjects.GetUmbracoSettings(),
Enumerable.Empty<IUrlProvider>(),
globalSettings,
new TestVariationContextAccessor(),
true);
new TestDefaultCultureAccessor(),
TestObjects.GetUmbracoSettings(),
globalSettings,
Enumerable.Empty<IUrlProvider>(),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
var umbCtx = umbracoContextReference.UmbracoContext;
var ctrl = new MatchesAsyncIndexController { UmbracoContext = umbCtx };
var controllerCtx = new ControllerContext(req, ctrl);
var result = attr.IsValidForRequest(controllerCtx,

View File

@@ -40,16 +40,19 @@ namespace Umbraco.Tests.Web.Mvc
public void Can_Construct_And_Get_Result()
{
var globalSettings = TestObjects.GetGlobalSettings();
var umbracoContext = UmbracoContext.EnsureContext(
var umbracoContextFactory = new UmbracoContextFactory(
Current.UmbracoContextAccessor,
new Mock<HttpContextBase>().Object,
Mock.Of<IPublishedSnapshotService>(),
new Mock<WebSecurity>(null, null, globalSettings).Object,
TestObjects.GetUmbracoSettings(),
Enumerable.Empty<IUrlProvider>(),
globalSettings,
new TestVariationContextAccessor(),
true);
new TestDefaultCultureAccessor(),
TestObjects.GetUmbracoSettings(),
globalSettings,
Enumerable.Empty<IUrlProvider>(),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
var umbracoContext = umbracoContextReference.UmbracoContext;
var ctrl = new TestSurfaceController(umbracoContext);
@@ -62,22 +65,25 @@ namespace Umbraco.Tests.Web.Mvc
public void Umbraco_Context_Not_Null()
{
var globalSettings = TestObjects.GetGlobalSettings();
var umbCtx = UmbracoContext.EnsureContext(
var umbracoContextFactory = new UmbracoContextFactory(
Current.UmbracoContextAccessor,
new Mock<HttpContextBase>().Object,
Mock.Of<IPublishedSnapshotService>(),
new Mock<WebSecurity>(null, null, globalSettings).Object,
TestObjects.GetUmbracoSettings(),
Enumerable.Empty<IUrlProvider>(),
globalSettings,
new TestVariationContextAccessor(),
true);
new TestDefaultCultureAccessor(),
TestObjects.GetUmbracoSettings(),
globalSettings,
Enumerable.Empty<IUrlProvider>(),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
var umbCtx = umbracoContextReference.UmbracoContext;
var ctrl = new TestSurfaceController(umbCtx);
Assert.IsNotNull(ctrl.UmbracoContext);
}
[Test]
public void Can_Lookup_Content()
{
@@ -88,16 +94,18 @@ namespace Umbraco.Tests.Web.Mvc
var publishedSnapshotService = new Mock<IPublishedSnapshotService>();
var globalSettings = TestObjects.GetGlobalSettings();
var umbracoContext = UmbracoContext.EnsureContext(
var umbracoContextFactory = new UmbracoContextFactory(
Current.UmbracoContextAccessor,
new Mock<HttpContextBase>().Object,
publishedSnapshotService.Object,
new Mock<WebSecurity>(null, null, globalSettings).Object,
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == "Auto")),
Enumerable.Empty<IUrlProvider>(),
globalSettings,
new TestVariationContextAccessor(),
true);
new TestDefaultCultureAccessor(),
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == "Auto")),
globalSettings,
Enumerable.Empty<IUrlProvider>(),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
var umbracoContext = umbracoContextReference.UmbracoContext;
var helper = new UmbracoHelper(
umbracoContext,
@@ -121,16 +129,18 @@ namespace Umbraco.Tests.Web.Mvc
var webRoutingSettings = Mock.Of<IWebRoutingSection>(section => section.UrlProviderMode == "Auto");
var globalSettings = TestObjects.GetGlobalSettings();
var umbracoContext = UmbracoContext.EnsureContext(
var umbracoContextFactory = new UmbracoContextFactory(
Current.UmbracoContextAccessor,
new Mock<HttpContextBase>().Object,
Mock.Of<IPublishedSnapshotService>(),
new Mock<WebSecurity>(null, null, globalSettings).Object,
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == webRoutingSettings),
Enumerable.Empty<IUrlProvider>(),
globalSettings,
new TestVariationContextAccessor(),
true);
new TestDefaultCultureAccessor(),
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == webRoutingSettings),
globalSettings,
Enumerable.Empty<IUrlProvider>(),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
var umbracoContext = umbracoContextReference.UmbracoContext;
var content = Mock.Of<IPublishedContent>(publishedContent => publishedContent.Id == 12345);

View File

@@ -96,20 +96,19 @@ namespace Umbraco.Tests.Web
var snapshotService = Mock.Of<IPublishedSnapshotService>();
Mock.Get(snapshotService).Setup(x => x.CreatePublishedSnapshot(It.IsAny<string>())).Returns(snapshot);
using (var umbCtx = UmbracoContext.EnsureContext(
var umbracoContextFactory = new UmbracoContextFactory(
Umbraco.Web.Composing.Current.UmbracoContextAccessor,
Mock.Of<HttpContextBase>(),
snapshotService,
new Mock<WebSecurity>(null, null, globalSettings).Object,
//setup a quick mock of the WebRouting section
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == "Auto")),
//pass in the custom url provider
new[]{ testUrlProvider.Object },
globalSettings,
new TestVariationContextAccessor(),
true))
new TestDefaultCultureAccessor(),
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == "Auto")),
globalSettings,
new[] { testUrlProvider.Object },
Mock.Of<IUserService>());
using (var reference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>()))
{
var output = TemplateUtilities.ParseInternalLinks(input, umbCtx.UrlProvider);
var output = TemplateUtilities.ParseInternalLinks(input, reference.UmbracoContext.UrlProvider);
Assert.AreEqual(result, output);
}

View File

@@ -16,17 +16,17 @@ namespace Umbraco.Web.Cache
{
private static readonly ConcurrentDictionary<string, MethodInfo> FoundHandlers = new ConcurrentDictionary<string, MethodInfo>();
private readonly DistributedCache _distributedCache;
private readonly IUmbracoContextFactory _umbracoContextFactory;
private readonly ILogger _logger;
/// <summary>
/// Initializes a new instance of the <see cref="DistributedCacheBinder"/> class.
/// </summary>
/// <param name="distributedCache"></param>
/// <param name="logger"></param>
public DistributedCacheBinder(DistributedCache distributedCache, ILogger logger)
public DistributedCacheBinder(DistributedCache distributedCache, IUmbracoContextFactory umbracoContextFactory, ILogger logger)
{
_distributedCache = distributedCache;
_logger = logger;
_umbracoContextFactory = umbracoContextFactory;
}
// internal for tests
@@ -64,7 +64,7 @@ namespace Umbraco.Web.Cache
{
// ensure we run with an UmbracoContext, because this may run in a background task,
// yet developers may be using the 'current' UmbracoContext in the event handlers
using (UmbracoContext.EnsureContext())
using (_umbracoContextFactory.EnsureUmbracoContext())
{
foreach (var e in events)
{

View File

@@ -44,7 +44,10 @@ namespace Umbraco.Web.Composing
CoreCurrent.Resetted += (sender, args) =>
{
if (_umbracoContextAccessor != null)
ClearUmbracoContext();
{
var umbracoContext = _umbracoContextAccessor.UmbracoContext;
umbracoContext?.Dispose();
}
_umbracoContextAccessor = null;
};
}
@@ -75,18 +78,6 @@ namespace Umbraco.Web.Composing
set => _umbracoContextAccessor = value; // for tests
}
// clears the "current" umbraco context
// at the moment the "current" umbraco context can end up being disposed and should get cleared
// in the accessor - this should be done differently but for the time being we have to support it
public static void ClearUmbracoContext()
{
lock (Locker)
{
UmbracoContextAccessor.UmbracoContext?.Dispose(); // dispose the one that is being cleared, if any
UmbracoContextAccessor.UmbracoContext = null;
}
}
#endregion
#region Web Getters

View File

@@ -69,7 +69,7 @@ namespace Umbraco.Web.Runtime
}
public void Initialize()
{
{
// setup mvc and webapi services
SetupMvcAndWebApi();
@@ -88,23 +88,6 @@ namespace Umbraco.Web.Runtime
// set routes
CreateRoutes(_umbracoContextAccessor, _globalSettings, _surfaceControllerTypes, _apiControllerTypes);
// get an http context
// at that moment, HttpContext.Current != null but its .Request property is null
var httpContext = new HttpContextWrapper(HttpContext.Current);
// ensure there is an UmbracoContext
// (also sets the accessor)
// this is a *temp* UmbracoContext
UmbracoContext.EnsureContext(
_umbracoContextAccessor,
new HttpContextWrapper(HttpContext.Current),
_publishedSnapshotService,
new WebSecurity(httpContext, _userService, _globalSettings),
_umbracoSettings,
_urlProviders,
_globalSettings,
_variationContextAccessor);
// ensure WebAPI is initialized, after everything
GlobalConfiguration.Configuration.EnsureInitialized();
}

View File

@@ -11,14 +11,16 @@ namespace Umbraco.Web.Scheduling
{
private readonly IRuntimeState _runtime;
private readonly IContentService _contentService;
private readonly IUmbracoContextFactory _umbracoContextFactory;
private readonly ILogger _logger;
public ScheduledPublishing(IBackgroundTaskRunner<RecurringTaskBase> runner, int delayMilliseconds, int periodMilliseconds,
IRuntimeState runtime, IContentService contentService, ILogger logger)
IRuntimeState runtime, IContentService contentService, IUmbracoContextFactory umbracoContextFactory, ILogger logger)
: base(runner, delayMilliseconds, periodMilliseconds)
{
_runtime = runtime;
_contentService = contentService;
_umbracoContextFactory = umbracoContextFactory;
_logger = logger;
}
@@ -62,7 +64,7 @@ namespace Umbraco.Web.Scheduling
// but then what should be its "scope"? could we attach it to scopes?
// - and we should definitively *not* have to flush it here (should be auto)
//
using (var tempContext = UmbracoContext.EnsureContext())
using (var contextReference = _umbracoContextFactory.EnsureUmbracoContext())
{
try
{
@@ -74,7 +76,7 @@ namespace Umbraco.Web.Scheduling
finally
{
// if running on a temp context, we have to flush the messenger
if (tempContext != null && Composing.Current.ServerMessenger is BatchedDatabaseServerMessenger m)
if (contextReference.IsRoot && Composing.Current.ServerMessenger is BatchedDatabaseServerMessenger m)
m.FlushBatch();
}
}

View File

@@ -24,6 +24,7 @@ namespace Umbraco.Web.Scheduling
private readonly IScopeProvider _scopeProvider;
private readonly HealthCheckCollection _healthChecks;
private readonly HealthCheckNotificationMethodCollection _notifications;
private readonly IUmbracoContextFactory _umbracoContextFactory;
private BackgroundTaskRunner<IBackgroundTask> _keepAliveRunner;
private BackgroundTaskRunner<IBackgroundTask> _publishingRunner;
@@ -38,13 +39,14 @@ namespace Umbraco.Web.Scheduling
public SchedulerComponent(IRuntimeState runtime,
IContentService contentService, IAuditService auditService,
HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications,
IScopeProvider scopeProvider, IProfilingLogger logger)
IScopeProvider scopeProvider, IUmbracoContextFactory umbracoContextFactory, IProfilingLogger logger)
{
_runtime = runtime;
_contentService = contentService;
_auditService = auditService;
_scopeProvider = scopeProvider;
_logger = logger;
_umbracoContextFactory = umbracoContextFactory;
_healthChecks = healthChecks;
_notifications = notifications;
@@ -114,11 +116,11 @@ namespace Umbraco.Web.Scheduling
{
// scheduled publishing/unpublishing
// install on all, will only run on non-replica servers
var task = new ScheduledPublishing(_publishingRunner, 60000, 60000, _runtime, _contentService, _logger);
var task = new ScheduledPublishing(_publishingRunner, 60000, 60000, _runtime, _contentService, _umbracoContextFactory, _logger);
_publishingRunner.TryAdd(task);
return task;
}
private IBackgroundTask RegisterHealthCheckNotifier(IHealthChecks healthCheckConfig,
HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications,
IProfilingLogger logger)

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Web;
using System.Web.Hosting;
using Umbraco.Core;
@@ -8,6 +9,7 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Services;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.Routing;
using Umbraco.Web.Runtime;
@@ -15,6 +17,117 @@ using Umbraco.Web.Security;
namespace Umbraco.Web
{
public interface IUmbracoContextFactory
{
UmbracoContextReference EnsureUmbracoContext(HttpContextBase httpContext = null);
}
public class UmbracoContextReference : IDisposable
{
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private bool _disposed;
internal UmbracoContextReference(UmbracoContext umbracoContext, bool isRoot, IUmbracoContextAccessor umbracoContextAccessor)
{
UmbracoContext = umbracoContext;
IsRoot = isRoot;
_umbracoContextAccessor = umbracoContextAccessor;
}
public UmbracoContext UmbracoContext { get; }
public bool IsRoot { get; }
public void Dispose()
{
if (_disposed)
return;
_disposed = true;
if (IsRoot)
{
UmbracoContext.Dispose();
_umbracoContextAccessor.UmbracoContext = null;
}
GC.SuppressFinalize(this);
}
}
public class UmbracoContextFactory : IUmbracoContextFactory
{
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IPublishedSnapshotService _publishedSnapshotService;
private readonly IVariationContextAccessor _variationContextAccessor;
private readonly IDefaultCultureAccessor _defaultCultureAccessor;
private readonly IUmbracoSettingsSection _umbracoSettings;
private readonly IGlobalSettings _globalSettings;
private readonly IEnumerable<IUrlProvider> _urlProviders;
private readonly IUserService _userService;
public UmbracoContextFactory(IUmbracoContextAccessor umbracoContextAccessor, IPublishedSnapshotService publishedSnapshotService, IVariationContextAccessor variationContextAccessor, IDefaultCultureAccessor defaultCultureAccessor, IUmbracoSettingsSection umbracoSettings, IGlobalSettings globalSettings, IEnumerable<IUrlProvider> urlProviders, IUserService userService)
{
_umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor));
_publishedSnapshotService = publishedSnapshotService ?? throw new ArgumentNullException(nameof(publishedSnapshotService));
_variationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor));
_defaultCultureAccessor = defaultCultureAccessor ?? throw new ArgumentNullException(nameof(defaultCultureAccessor));
_umbracoSettings = umbracoSettings ?? throw new ArgumentNullException(nameof(umbracoSettings));
_globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings));
_urlProviders = urlProviders ?? throw new ArgumentNullException(nameof(urlProviders));
_userService = userService ?? throw new ArgumentNullException(nameof(userService));
}
public UmbracoContext CreateUmbracoContext(HttpContextBase httpContext)
{
// make sure we have a variation context
if (_variationContextAccessor.VariationContext == null)
_variationContextAccessor.VariationContext = new VariationContext(_defaultCultureAccessor.DefaultCulture);
var webSecurity = new WebSecurity(httpContext, _userService, _globalSettings);
return new UmbracoContext(httpContext, _publishedSnapshotService, webSecurity, _umbracoSettings, _urlProviders, _globalSettings, _variationContextAccessor);
}
public UmbracoContext EnsureUmbracoContext___(HttpContextBase httpContext)
{
var currentUmbracoContext = _umbracoContextAccessor.UmbracoContext;
if (currentUmbracoContext != null)
{
currentUmbracoContext.Dispose();
_umbracoContextAccessor.UmbracoContext = null;
}
var umbracoContext = CreateUmbracoContext(httpContext);
_umbracoContextAccessor.UmbracoContext = umbracoContext;
return umbracoContext;
}
public UmbracoContextReference EnsureUmbracoContext(HttpContextBase httpContext = null)
{
var currentUmbracoContext = _umbracoContextAccessor.UmbracoContext;
if (currentUmbracoContext != null) return new UmbracoContextReference(currentUmbracoContext, false, _umbracoContextAccessor);
httpContext = httpContext ?? new HttpContextWrapper(HttpContext.Current ?? new HttpContext(new SimpleWorkerRequest("nul.aspx", "", NulWriter.Instance)));
var umbracoContext = CreateUmbracoContext(httpContext);
_umbracoContextAccessor.UmbracoContext = umbracoContext;
return new UmbracoContextReference(umbracoContext, true, _umbracoContextAccessor);
}
private class NulWriter : TextWriter
{
private NulWriter()
{ }
public static NulWriter Instance { get; } = new NulWriter();
public override Encoding Encoding => Encoding.UTF8;
}
}
/// <summary>
/// Class that encapsulates Umbraco information of a specific HTTP request
/// </summary>
@@ -26,102 +139,6 @@ namespace Umbraco.Web
private string _previewToken;
private bool? _previewing;
#region Ensure Context
/// <summary>
/// Ensures that there is a "current" UmbracoContext.
/// </summary>
/// <param name="umbracoContextAccessor"></param>
/// <param name="httpContext">An http context.</param>
/// <param name="publishedSnapshotService">A published snapshot service.</param>
/// <param name="webSecurity">A security helper.</param>
/// <param name="umbracoSettings">The umbraco settings.</param>
/// <param name="urlProviders">Some url providers.</param>
/// <param name="globalSettings"></param>
/// <param name="replace">A value indicating whether to replace the existing context.</param>
/// <returns>The "current" UmbracoContext.</returns>
/// <remarks>
/// TODO: this needs to be clarified
///
/// If <paramref name="replace"/> is true then the "current" UmbracoContext is replaced
/// with a new one even if there is one already. See <see cref="WebRuntimeComponent"/>. Has to do with
/// creating a context at startup and not being able to access httpContext.Request at that time, so
/// the OriginalRequestUrl remains unspecified until <see cref="UmbracoModule"/> replaces the context.
///
/// This *has* to be done differently!
///
/// See http://issues.umbraco.org/issue/U4-1890, http://issues.umbraco.org/issue/U4-1717
///
/// </remarks>
// used by
// UmbracoModule BeginRequest (since it's a request it has an UmbracoContext)
// in BeginRequest so *late* ie *after* the HttpApplication has started (+ init? check!)
// WebRuntimeComponent (and I'm not quite sure why)
// -> because an UmbracoContext seems to be required by UrlProvider to get the "current" published snapshot?
// note: at startup not sure we have an HttpContext.Current
// at startup not sure we have an httpContext.Request => hard to tell "current" url
// should we have a post-boot event of some sort for ppl that *need* ?!
// can we have issues w/ routing context?
// and tests
// can .ContentRequest be null? of course!
public static UmbracoContext EnsureContext(
IUmbracoContextAccessor umbracoContextAccessor,
HttpContextBase httpContext,
IPublishedSnapshotService publishedSnapshotService,
WebSecurity webSecurity,
IUmbracoSettingsSection umbracoSettings,
IEnumerable<IUrlProvider> urlProviders,
IGlobalSettings globalSettings,
IVariationContextAccessor variationContextAccessor,
bool replace = false)
{
if (umbracoContextAccessor == null) throw new ArgumentNullException(nameof(umbracoContextAccessor));
if (httpContext == null) throw new ArgumentNullException(nameof(httpContext));
if (publishedSnapshotService == null) throw new ArgumentNullException(nameof(publishedSnapshotService));
if (webSecurity == null) throw new ArgumentNullException(nameof(webSecurity));
if (umbracoSettings == null) throw new ArgumentNullException(nameof(umbracoSettings));
if (urlProviders == null) throw new ArgumentNullException(nameof(urlProviders));
if (globalSettings == null) throw new ArgumentNullException(nameof(globalSettings));
// if there is already a current context, return if not replacing
var current = umbracoContextAccessor.UmbracoContext;
if (current != null && replace == false)
return current;
// create & assign to accessor, dispose existing if any
umbracoContextAccessor.UmbracoContext?.Dispose();
return umbracoContextAccessor.UmbracoContext = new UmbracoContext(httpContext, publishedSnapshotService, webSecurity, umbracoSettings, urlProviders, globalSettings, variationContextAccessor);
}
/// <summary>
/// Gets a disposable object representing the presence of a current UmbracoContext.
/// </summary>
/// <remarks>
/// <para>The disposable object should be used in a using block: using (UmbracoContext.EnsureContext()) { ... }.</para>
/// <para>If an actual current UmbracoContext is already present, the disposable object is null and this method does nothing.</para>
/// <para>Otherwise, a temporary, dummy UmbracoContext is created and registered in the accessor. And disposed and removed from the accessor.</para>
/// </remarks>
internal static IDisposable EnsureContext(HttpContextBase httpContext = null) // keep this internal for now!
{
if (Composing.Current.UmbracoContext != null) return null;
httpContext = httpContext ?? new HttpContextWrapper(System.Web.HttpContext.Current ?? new HttpContext(new SimpleWorkerRequest("temp.aspx", "", new StringWriter())));
return EnsureContext(
Composing.Current.UmbracoContextAccessor,
httpContext,
Composing.Current.PublishedSnapshotService,
new WebSecurity(httpContext, Composing.Current.Services.UserService, Composing.Current.Configs.Global()),
Composing.Current.Configs.Settings(),
Composing.Current.UrlProviders,
Composing.Current.Configs.Global(),
Composing.Current.Factory.GetInstance<IVariationContextAccessor>(),
true);
// when the context will be disposed, it will be removed from the accessor
// (see DisposeResources)
}
// initializes a new instance of the UmbracoContext class
// internal for unit tests
// otherwise it's used by EnsureContext above
@@ -172,8 +189,6 @@ namespace Umbraco.Web
UrlProvider = new UrlProvider(this, umbracoSettings.WebRouting, urlProviders, variationContextAccessor);
}
#endregion
/// <summary>
/// This is used internally for performance calculations, the ObjectCreated DateTime is set as soon as this
/// object is instantiated which in the web site is created during the BeginRequest phase.
@@ -339,10 +354,6 @@ namespace Umbraco.Web
Security.DisposeIfDisposable();
// reset - important when running outside of http context
// also takes care of the accessor
Composing.Current.ClearUmbracoContext();
// help caches release resources
// (but don't create caches just to dispose them)
// context is not multi-threaded

View File

@@ -47,6 +47,7 @@ namespace Umbraco.Web
private readonly ILogger _logger;
private readonly IPublishedRouter _publishedRouter;
private readonly IVariationContextAccessor _variationContextAccessor;
private readonly IUmbracoContextFactory _umbracoContextFactory;
public UmbracoInjectedModule(
IGlobalSettings globalSettings,
@@ -57,7 +58,8 @@ namespace Umbraco.Web
IRuntimeState runtime,
ILogger logger,
IPublishedRouter publishedRouter,
IVariationContextAccessor variationContextAccessor)
IVariationContextAccessor variationContextAccessor,
IUmbracoContextFactory umbracoContextFactory)
{
_combinedRouteCollection = new Lazy<RouteCollection>(CreateRouteCollection);
@@ -70,6 +72,7 @@ namespace Umbraco.Web
_logger = logger;
_publishedRouter = publishedRouter;
_variationContextAccessor = variationContextAccessor;
_umbracoContextFactory = umbracoContextFactory;
}
#region HttpModule event handlers
@@ -92,18 +95,10 @@ namespace Umbraco.Web
// ok, process
// create the UmbracoContext singleton, one per request, and assign
// replace existing if any (eg during app startup, a temp one is created)
UmbracoContext.EnsureContext(
_umbracoContextAccessor,
httpContext,
_publishedSnapshotService,
new WebSecurity(httpContext, _userService, _globalSettings),
Current.Configs.Settings(),
_urlProviders,
_globalSettings,
_variationContextAccessor,
true);
// ensure there's an UmbracoContext registered for the current request
// registers the context reference so its disposed at end of request
var umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext(httpContext);
httpContext.DisposeOnPipelineCompleted(umbracoContextReference);
}
/// <summary>