Merge pull request #4577 from umbraco/temp8-contexts

Refactor UmbracoContext
This commit is contained in:
Shannon Deminick
2019-02-15 12:55:29 +11:00
committed by GitHub
68 changed files with 487 additions and 434 deletions

View File

@@ -1,64 +0,0 @@
using System;
namespace Umbraco.Core
{
/// <summary>
/// Abstract implementation of IDisposable.
/// </summary>
/// <remarks>
/// This is for objects that DO have unmanaged resources. Use <see cref="DisposableObjectSlim"/>
/// for objects that do NOT have unmanaged resources, and avoid creating a finalizer.
///
/// Can also be used as a pattern for when inheriting is not possible.
///
/// See also: https://msdn.microsoft.com/en-us/library/b1yfkh5e%28v=vs.110%29.aspx
/// See also: https://lostechies.com/chrispatterson/2012/11/29/idisposable-done-right/
///
/// Note: if an object's ctor throws, it will never be disposed, and so if that ctor
/// has allocated disposable objects, it should take care of disposing them.
/// </remarks>
public abstract class DisposableObject : IDisposable
{
private readonly object _locko = new object();
// gets a value indicating whether this instance is disposed.
// for internal tests only (not thread safe)
public bool Disposed { get; private set; }
// implements IDisposable
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// finalizer
~DisposableObject()
{
Dispose(false);
}
private void Dispose(bool disposing)
{
// can happen if the object construction failed
if (_locko == null)
return;
lock (_locko)
{
if (Disposed) return;
Disposed = true;
}
DisposeUnmanagedResources();
if (disposing)
DisposeResources();
}
protected abstract void DisposeResources();
protected virtual void DisposeUnmanagedResources()
{ }
}
}

View File

@@ -41,7 +41,7 @@ namespace Umbraco.Core.Logging
}
// a lightweight disposable timer
private class LightDisposableTimer : DisposableObject
private class LightDisposableTimer : DisposableObjectSlim
{
private readonly Action<long> _callback;
private readonly Stopwatch _stopwatch = Stopwatch.StartNew();

View File

@@ -22,7 +22,7 @@ namespace Umbraco.Core.Logging
public void Stop(bool discardResults = false)
{ }
private class VoidDisposable : DisposableObject
private class VoidDisposable : DisposableObjectSlim
{
protected override void DisposeResources()
{ }

View File

@@ -24,7 +24,7 @@ namespace Umbraco.Core.Persistence
/// </remarks>
// TODO: these comments are not true anymore
// TODO: this class needs not be disposable!
internal class UmbracoDatabaseFactory : DisposableObject, IUmbracoDatabaseFactory
internal class UmbracoDatabaseFactory : DisposableObjectSlim, IUmbracoDatabaseFactory
{
private readonly Lazy<IMapperCollection> _mappers;
private readonly ILogger _logger;

View File

@@ -561,7 +561,6 @@
<Compile Include="DictionaryExtensions.cs" />
<Compile Include="Dictionary\ICultureDictionary.cs" />
<Compile Include="Dictionary\ICultureDictionaryFactory.cs" />
<Compile Include="DisposableObject.cs" />
<Compile Include="Logging\DisposableTimer.cs" />
<Compile Include="EmailSender.cs" />
<Compile Include="Enum.cs" />

View File

@@ -4,11 +4,14 @@ using System.Threading;
using Moq;
using NUnit.Framework;
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;
@@ -148,8 +151,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

@@ -51,10 +51,13 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
return new ForcedPreviewObject();
}
private class ForcedPreviewObject : DisposableObject
private class ForcedPreviewObject : DisposableObjectSlim
{
protected override void DisposeResources()
{ }
}
public void Dispose()
{ }
}
}

View File

@@ -13,7 +13,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
{
get
{
var umbracoContext = UmbracoContext.Current;
var umbracoContext = Umbraco.Web.Composing.Current.UmbracoContext;
// will get or create a value
// a ConditionalWeakTable is thread-safe

View File

@@ -4,12 +4,12 @@ using System.Collections.ObjectModel;
using System.Linq;
using Moq;
using NUnit.Framework;
using Umbraco.Core.Composing;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Services;
using Umbraco.Tests.Testing;
using Umbraco.Web;
using Current = Umbraco.Web.Composing.Current;
namespace Umbraco.Tests.PublishedContent
{
@@ -186,7 +186,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Can_Get_Content_For_Populated_Requested_Language()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot().First();
var content = Current.UmbracoContext.ContentCache.GetAtRoot().First();
var value = content.Value("welcomeText", "en-US");
Assert.AreEqual("Welcome", value);
}
@@ -194,7 +194,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Can_Get_Content_For_Populated_Requested_Non_Default_Language()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot().First();
var content = Current.UmbracoContext.ContentCache.GetAtRoot().First();
var value = content.Value("welcomeText", "de");
Assert.AreEqual("Willkommen", value);
}
@@ -202,7 +202,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Do_Not_Get_Content_For_Unpopulated_Requested_Language_Without_Fallback()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot().First();
var content = Current.UmbracoContext.ContentCache.GetAtRoot().First();
var value = content.Value("welcomeText", "fr");
Assert.IsNull(value);
}
@@ -210,7 +210,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Do_Not_Get_Content_For_Unpopulated_Requested_Language_With_Fallback_Unless_Requested()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot().First();
var content = Current.UmbracoContext.ContentCache.GetAtRoot().First();
var value = content.Value("welcomeText", "es");
Assert.IsNull(value);
}
@@ -218,7 +218,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Can_Get_Content_For_Unpopulated_Requested_Language_With_Fallback()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot().First();
var content = Current.UmbracoContext.ContentCache.GetAtRoot().First();
var value = content.Value("welcomeText", "es", fallback: Fallback.ToLanguage);
Assert.AreEqual("Welcome", value);
}
@@ -226,7 +226,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Can_Get_Content_For_Unpopulated_Requested_Language_With_Fallback_Over_Two_Levels()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot().First();
var content = Current.UmbracoContext.ContentCache.GetAtRoot().First();
var value = content.Value("welcomeText", "it", fallback: Fallback.To(Fallback.Language, Fallback.Ancestors));
Assert.AreEqual("Welcome", value);
}
@@ -234,7 +234,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Do_Not_GetContent_For_Unpopulated_Requested_Language_With_Fallback_Over_That_Loops()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot().First();
var content = Current.UmbracoContext.ContentCache.GetAtRoot().First();
var value = content.Value("welcomeText", "no", fallback: Fallback.ToLanguage);
Assert.IsNull(value);
}
@@ -242,7 +242,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Do_Not_Get_Content_Recursively_Unless_Requested()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot().First().Children.First();
var content = Current.UmbracoContext.ContentCache.GetAtRoot().First().Children.First();
var value = content.Value("welcomeText2");
Assert.IsNull(value);
}
@@ -250,7 +250,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Can_Get_Content_Recursively()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot().First().Children.First();
var content = Current.UmbracoContext.ContentCache.GetAtRoot().First().Children.First();
var value = content.Value("welcomeText2", fallback: Fallback.ToAncestors);
Assert.AreEqual("Welcome", value);
}
@@ -258,7 +258,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Do_Not_Get_Content_Recursively_Unless_Requested2()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot().First().Children.First().Children().First();
var content = Current.UmbracoContext.ContentCache.GetAtRoot().First().Children.First().Children().First();
Assert.IsNull(content.GetProperty("welcomeText2"));
var value = content.Value("welcomeText2");
Assert.IsNull(value);
@@ -267,7 +267,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Can_Get_Content_Recursively2()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot().First().Children.First().Children().First();
var content = Current.UmbracoContext.ContentCache.GetAtRoot().First().Children.First().Children().First();
Assert.IsNull(content.GetProperty("welcomeText2"));
var value = content.Value("welcomeText2", fallback: Fallback.ToAncestors);
Assert.AreEqual("Welcome", value);
@@ -276,7 +276,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Can_Get_Content_Recursively3()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot().First().Children.First().Children().First();
var content = Current.UmbracoContext.ContentCache.GetAtRoot().First().Children.First().Children().First();
Assert.IsNull(content.GetProperty("noprop"));
var value = content.Value("noprop", fallback: Fallback.ToAncestors);
// property has no value but we still get the value (ie, the converter would do something)
@@ -287,7 +287,7 @@ namespace Umbraco.Tests.PublishedContent
public void Can_Get_Content_With_Recursive_Priority()
{
Current.VariationContextAccessor.VariationContext = new VariationContext("nl");
var content = UmbracoContext.Current.ContentCache.GetAtRoot().First().Children.First();
var content = Current.UmbracoContext.ContentCache.GetAtRoot().First().Children.First();
var value = content.Value("welcomeText", "nl", fallback: Fallback.To(Fallback.Ancestors, Fallback.Language));
@@ -298,7 +298,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Can_Get_Content_With_Fallback_Language_Priority()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot().First().Children.First();
var content = Current.UmbracoContext.ContentCache.GetAtRoot().First().Children.First();
var value = content.Value("welcomeText", "nl", fallback: Fallback.ToLanguage);
// No Dutch value is directly assigned. Check has fallen back to English value from language variant.
@@ -308,14 +308,14 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Throws_For_Non_Supported_Fallback()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot().First().Children.First();
var content = Current.UmbracoContext.ContentCache.GetAtRoot().First().Children.First();
Assert.Throws<NotSupportedException>(() => content.Value("welcomeText", "nl", fallback: Fallback.To(999)));
}
[Test]
public void Can_Fallback_To_Default_Value()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot().First().Children.First();
var content = Current.UmbracoContext.ContentCache.GetAtRoot().First().Children.First();
// no Dutch value is assigned, so getting null
var value = content.Value("welcomeText", "nl");
@@ -333,7 +333,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Can_Have_Custom_Default_Value()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot().First().Children.First();
var content = Current.UmbracoContext.ContentCache.GetAtRoot().First().Children.First();
// HACK: the value, pretend the converter would return something
var prop = content.GetProperty("welcomeText") as SolidPublishedPropertyWithLanguageVariants;

View File

@@ -5,6 +5,7 @@ using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web;
using Umbraco.Core;
using Umbraco.Tests.Testing;
using Umbraco.Web.Composing;
namespace Umbraco.Tests.PublishedContent
{
@@ -95,14 +96,14 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void First()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot().First();
var content = Current.UmbracoContext.ContentCache.GetAtRoot().First();
Assert.AreEqual("Content 1", content.Name);
}
[Test]
public void Distinct()
{
var items = UmbracoContext.Current.ContentCache.GetAtRoot()
var items = Current.UmbracoContext.ContentCache.GetAtRoot()
.Distinct()
.Distinct()
.ToIndexedArray();
@@ -126,7 +127,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void OfType1()
{
var items = UmbracoContext.Current.ContentCache.GetAtRoot()
var items = Current.UmbracoContext.ContentCache.GetAtRoot()
.OfType<ContentType2>()
.Distinct()
.ToIndexedArray();
@@ -137,7 +138,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void OfType2()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot()
var content = Current.UmbracoContext.ContentCache.GetAtRoot()
.OfType<ContentType2Sub>()
.Distinct()
.ToIndexedArray();
@@ -148,7 +149,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void OfType()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot()
var content = Current.UmbracoContext.ContentCache.GetAtRoot()
.OfType<ContentType2>()
.First(x => x.Prop1 == 1234);
Assert.AreEqual("Content 2", content.Name);
@@ -158,7 +159,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Position()
{
var items = UmbracoContext.Current.ContentCache.GetAtRoot()
var items = Current.UmbracoContext.ContentCache.GetAtRoot()
.Where(x => x.Value<int>("prop1") == 1234)
.ToIndexedArray();
@@ -173,7 +174,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Issue()
{
var content = UmbracoContext.Current.ContentCache.GetAtRoot()
var content = Current.UmbracoContext.ContentCache.GetAtRoot()
.Distinct()
.OfType<ContentType2>();
@@ -181,12 +182,12 @@ namespace Umbraco.Tests.PublishedContent
var first = where.First();
Assert.AreEqual(1234, first.Prop1);
var content2 = UmbracoContext.Current.ContentCache.GetAtRoot()
var content2 = Current.UmbracoContext.ContentCache.GetAtRoot()
.OfType<ContentType2>()
.First(x => x.Prop1 == 1234);
Assert.AreEqual(1234, content2.Prop1);
var content3 = UmbracoContext.Current.ContentCache.GetAtRoot()
var content3 = Current.UmbracoContext.ContentCache.GetAtRoot()
.OfType<ContentType2>()
.First();
Assert.AreEqual(1234, content3.Prop1);
@@ -195,7 +196,7 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void PublishedContentQueryTypedContentList()
{
var query = new PublishedContentQuery(UmbracoContext.Current.PublishedSnapshot, UmbracoContext.Current.VariationContextAccessor);
var query = new PublishedContentQuery(Current.UmbracoContext.PublishedSnapshot, Current.UmbracoContext.VariationContextAccessor);
var result = query.Content(new[] { 1, 2, 4 }).ToArray();
Assert.AreEqual(2, result.Length);
Assert.AreEqual(1, result[0].Id);

View File

@@ -39,6 +39,9 @@ namespace Umbraco.Tests.PublishedContent
public IAppCache SnapshotCache => null;
public IAppCache ElementsCache => null;
public void Dispose()
{ }
}
class SolidPublishedContentCache : PublishedCacheBase, IPublishedContentCache, IPublishedMediaCache

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

@@ -100,6 +100,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>()
@@ -178,8 +179,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);
@@ -217,7 +219,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

@@ -15,6 +15,7 @@ using Umbraco.Core;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Sync;
using Umbraco.Web;
namespace Umbraco.Tests.Scoping
{
@@ -74,7 +75,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);
@@ -155,7 +156,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);
@@ -247,7 +248,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

@@ -16,6 +16,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;
@@ -92,7 +93,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"
@@ -205,7 +206,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,16 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
var umbracoContextAccessor = Umbraco.Web.Composing.Current.UmbracoContextAccessor;
var umbCtx = UmbracoContext.EnsureContext(
umbracoContextAccessor,
httpContext,
var umbCtx = new UmbracoContext(httpContext,
publishedSnapshotService.Object,
webSecurity.Object,
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == UrlProviderMode.Auto.ToString())),
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == "Auto")),
Enumerable.Empty<IUrlProvider>(),
globalSettings,
new TestVariationContextAccessor(),
true); //replace it
new TestVariationContextAccessor());
//replace it
umbracoContextAccessor.UmbracoContext = umbCtx;
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

@@ -44,7 +44,7 @@ namespace Umbraco.Tests.Testing.TestingTests
public void Can_Mock_Umbraco_Context()
{
var umbracoContext = TestObjects.GetUmbracoContextMock(Current.UmbracoContextAccessor);
Assert.AreEqual(umbracoContext, UmbracoContext.Current);
Assert.AreEqual(umbracoContext, Current.UmbracoContext);
}
[Test]

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

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.WebPages;
using Umbraco.Web.Composing;
namespace Umbraco.Web.UI.Config.Splashes
{
@@ -13,7 +14,7 @@ namespace Umbraco.Web.UI.Config.Splashes
{
base.OnInit(e);
var store = UmbracoContext.Current.ContentCache;
var store = Current.UmbracoContext.ContentCache;
if (store.HasContent())
{
//if there is actually content, go to the root

View File

@@ -12,6 +12,7 @@ using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Scoping;
using Umbraco.Web.Composing;
namespace Umbraco.Web
{
@@ -102,7 +103,7 @@ namespace Umbraco.Web
// try get the http context from the UmbracoContext, we do this because in the case we are launching an async
// thread and we know that the cache refreshers will execute, we will ensure the UmbracoContext and therefore we
// can get the http context from it
var httpContext = (UmbracoContext.Current == null ? null : UmbracoContext.Current.HttpContext)
var httpContext = (Current.UmbracoContext == null ? null : Current.UmbracoContext.HttpContext)
// if this is null, it could be that an async thread is calling this method that we weren't aware of and the UmbracoContext
// wasn't ensured at the beginning of the thread. We can try to see if the HttpContext.Current is available which might be
// the case if the asp.net synchronization context has kicked in

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

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Net.Http;
using System.Web.Http.Filters;
using Umbraco.Web.Composing;
using Umbraco.Web.Models.ContentEditing;
namespace Umbraco.Web.Editors.Filters
@@ -14,7 +15,7 @@ namespace Umbraco.Web.Editors.Filters
{
if (actionExecutedContext.Response == null) return;
var user = UmbracoContext.Current.Security.CurrentUser;
var user = Current.UmbracoContext.Security.CurrentUser;
if (user == null) return;
var objectContent = actionExecutedContext.Response.Content as ObjectContent;

View File

@@ -35,7 +35,7 @@ namespace Umbraco.Web.Editors.Filters
private UmbracoContext GetUmbracoContext()
{
return _umbracoContext ?? UmbracoContext.Current;
return _umbracoContext ?? Composing.Current.UmbracoContext;
}
protected override bool IsAuthorized(HttpActionContext actionContext)

View File

@@ -71,7 +71,7 @@ namespace Umbraco.Web.Editors
}
}
//Get all allowed sections for the current user
var allowedSections = UmbracoContext.Current.Security.CurrentUser.AllowedSections.ToList();
var allowedSections = Composing.Current.UmbracoContext.Security.CurrentUser.AllowedSections.ToList();
var toursToBeRemoved = new List<BackOfficeTourFile>();

View File

@@ -63,12 +63,12 @@ namespace Umbraco.Web
/// </remarks>
public static MvcHtmlString PreviewBadge(this HtmlHelper helper)
{
if (UmbracoContext.Current.InPreviewMode)
if (Current.UmbracoContext.InPreviewMode)
{
var htmlBadge =
String.Format(Current.Configs.Settings().Content.PreviewBadge,
IOHelper.ResolveUrl(SystemDirectories.Umbraco),
UmbracoContext.Current.HttpContext.Server.UrlEncode(UmbracoContext.Current.HttpContext.Request.Path));
Current.UmbracoContext.HttpContext.Server.UrlEncode(Current.UmbracoContext.HttpContext.Request.Path));
return new MvcHtmlString(htmlBadge);
}
return new MvcHtmlString("");
@@ -88,11 +88,11 @@ namespace Umbraco.Web
var cacheKey = new StringBuilder(partialViewName);
if (cacheByPage)
{
if (UmbracoContext.Current == null)
if (Current.UmbracoContext == null)
{
throw new InvalidOperationException("Cannot cache by page if the UmbracoContext has not been initialized, this parameter can only be used in the context of an Umbraco request");
}
cacheKey.AppendFormat("{0}-", UmbracoContext.Current.PublishedRequest?.PublishedContent?.Id ?? 0);
cacheKey.AppendFormat("{0}-", Current.UmbracoContext.PublishedRequest?.PublishedContent?.Id ?? 0);
}
if (cacheByMember)
{
@@ -690,7 +690,7 @@ namespace Umbraco.Web
if (string.IsNullOrEmpty(action)) throw new ArgumentNullOrEmptyException(nameof(action));
if (string.IsNullOrEmpty(controllerName)) throw new ArgumentNullOrEmptyException(nameof(controllerName));
var formAction = UmbracoContext.Current.OriginalRequestUrl.PathAndQuery;
var formAction = Current.UmbracoContext.OriginalRequestUrl.PathAndQuery;
return html.RenderForm(formAction, method, htmlAttributes, controllerName, action, area, additionalRouteVals);
}

View File

@@ -0,0 +1,32 @@
using System.Web;
namespace Umbraco.Web
{
/// <summary>
/// Creates and manages <see cref="UmbracoContext"/> instances.
/// </summary>
public interface IUmbracoContextFactory
{
/// <summary>
/// Ensures that a current <see cref="UmbracoContext"/> exists.
/// </summary>
/// <remarks>
/// <para>If an <see cref="UmbracoContext"/> is already registered in the
/// <see cref="IUmbracoContextAccessor"/>, returns a non-root reference to it.
/// Otherwise, create a new instance, registers it, and return a root reference
/// to it.</para>
/// <para>If <paramref name="httpContext"/> is null, the factory tries to use
/// <see cref="HttpContext.Current"/> if it exists. Otherwise, it uses a dummy
/// <see cref="HttpContextBase"/>.</para>
/// </remarks>
/// <example>
/// using (var contextReference = contextFactory.EnsureUmbracoContext())
/// {
/// var umbracoContext = contextReference.UmbracoContext;
/// // use umbracoContext...
/// }
/// </example>
/// <param name="httpContext">An optional http context.</param>
UmbracoContextReference EnsureUmbracoContext(HttpContextBase httpContext = null);
}
}

View File

@@ -6,6 +6,7 @@ using System.Web.WebPages;
using Umbraco.Web.Mvc;
using Umbraco.Core;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Composing;
namespace Umbraco.Web.Macros
{
@@ -28,9 +29,9 @@ namespace Umbraco.Web.Macros
_getUmbracoContext = () =>
{
if (UmbracoContext.Current == null)
if (Current.UmbracoContext == null)
throw new InvalidOperationException($"The {GetType()} cannot execute with a null UmbracoContext.Current reference.");
return UmbracoContext.Current;
return Current.UmbracoContext;
};
}

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Web.Composing;
namespace Umbraco.Web.Models.Mapping
{
@@ -23,7 +24,7 @@ namespace Umbraco.Web.Models.Mapping
public IEnumerable<string> Resolve(IContent source)
{
//cannot check permissions without a context
if (UmbracoContext.Current == null)
if (Current.UmbracoContext == null)
return Enumerable.Empty<string>();
string path;
@@ -38,7 +39,7 @@ namespace Umbraco.Web.Models.Mapping
// TODO: This is certainly not ideal usage here - perhaps the best way to deal with this in the future is
// with the IUmbracoContextAccessor. In the meantime, if used outside of a web app this will throw a null
// reference exception :(
return UserService.GetPermissionsForPath(UmbracoContext.Current.Security.CurrentUser, path).GetAllPermissions();
return UserService.GetPermissionsForPath(Current.UmbracoContext.Security.CurrentUser, path).GetAllPermissions();
}
}
}

View File

@@ -5,6 +5,7 @@ using AutoMapper;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Web.Composing;
using Umbraco.Web.Models.ContentEditing;
namespace Umbraco.Web.Models.Mapping
@@ -27,8 +28,8 @@ namespace Umbraco.Web.Models.Mapping
{
// TODO: We can resolve the UmbracoContext from the IValueResolver options!
// OMG
if (HttpContext.Current != null && UmbracoContext.Current != null && UmbracoContext.Current.Security.CurrentUser != null
&& UmbracoContext.Current.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings)))
if (HttpContext.Current != null && Current.UmbracoContext != null && Current.UmbracoContext.Security.CurrentUser != null
&& Current.UmbracoContext.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings)))
{
var contentType = _contentTypeBaseServiceProvider.GetContentTypeOf(source);
var contentTypeBasic = Mapper.Map<IContentTypeComposition, ContentTypeBasic>(contentType);

View File

@@ -69,7 +69,7 @@ namespace Umbraco.Web.Mvc
/// <summary>
/// Exposes the UmbracoContext
/// </summary>
protected UmbracoContext UmbracoContext => _umbracoContext ?? (_umbracoContext = UmbracoContext.Current);
protected UmbracoContext UmbracoContext => _umbracoContext ?? (_umbracoContext = Current.UmbracoContext);
// TODO: try lazy property injection?
private IPublishedRouter PublishedRouter => Core.Composing.Current.Factory.GetInstance<IPublishedRouter>();
@@ -84,13 +84,13 @@ namespace Umbraco.Web.Mvc
base.OnActionExecuted(filterContext);
// First we need to check if the published content request has been set, if it has we're going to ignore this and not actually do anything
if (UmbracoContext.Current.PublishedRequest != null)
if (Current.UmbracoContext.PublishedRequest != null)
{
return;
}
UmbracoContext.Current.PublishedRequest = PublishedRouter.CreateRequest(UmbracoContext.Current);
ConfigurePublishedContentRequest(UmbracoContext.Current.PublishedRequest, filterContext);
Current.UmbracoContext.PublishedRequest = PublishedRouter.CreateRequest(Current.UmbracoContext);
ConfigurePublishedContentRequest(Current.UmbracoContext.PublishedRequest, filterContext);
}
/// <summary>

View File

@@ -6,6 +6,7 @@ using System.Web.Mvc;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Composing;
namespace Umbraco.Web.Mvc
{
@@ -55,7 +56,7 @@ namespace Umbraco.Web.Mvc
if (_publishedContent != null) return _publishedContent;
//need to get the URL for the page
_publishedContent = UmbracoContext.Current.ContentCache.GetById(_pageId);
_publishedContent = Current.UmbracoContext.ContentCache.GetById(_pageId);
return _publishedContent;
}
@@ -66,7 +67,7 @@ namespace Umbraco.Web.Mvc
/// </summary>
/// <param name="pageId"></param>
public RedirectToUmbracoPageResult(int pageId)
: this(pageId, UmbracoContext.Current)
: this(pageId, Current.UmbracoContext)
{
}
@@ -76,7 +77,7 @@ namespace Umbraco.Web.Mvc
/// <param name="pageId"></param>
/// <param name="queryStringValues"></param>
public RedirectToUmbracoPageResult(int pageId, NameValueCollection queryStringValues)
: this(pageId, queryStringValues, UmbracoContext.Current)
: this(pageId, queryStringValues, Current.UmbracoContext)
{
}
@@ -86,7 +87,7 @@ namespace Umbraco.Web.Mvc
/// <param name="pageId"></param>
/// <param name="queryString"></param>
public RedirectToUmbracoPageResult(int pageId, string queryString)
: this(pageId, queryString, UmbracoContext.Current)
: this(pageId, queryString, Current.UmbracoContext)
{
}
@@ -95,7 +96,7 @@ namespace Umbraco.Web.Mvc
/// </summary>
/// <param name="publishedContent"></param>
public RedirectToUmbracoPageResult(IPublishedContent publishedContent)
: this(publishedContent, UmbracoContext.Current)
: this(publishedContent, Current.UmbracoContext)
{
}
@@ -105,7 +106,7 @@ namespace Umbraco.Web.Mvc
/// <param name="publishedContent"></param>
/// <param name="queryStringValues"></param>
public RedirectToUmbracoPageResult(IPublishedContent publishedContent, NameValueCollection queryStringValues)
: this(publishedContent, queryStringValues, UmbracoContext.Current)
: this(publishedContent, queryStringValues, Current.UmbracoContext)
{
}
@@ -115,7 +116,7 @@ namespace Umbraco.Web.Mvc
/// <param name="queryString"></param>
/// <param name="queryStringValues"></param>
public RedirectToUmbracoPageResult(IPublishedContent publishedContent, string queryString)
: this(publishedContent, queryString, UmbracoContext.Current)
: this(publishedContent, queryString, Current.UmbracoContext)
{
}

View File

@@ -206,7 +206,7 @@ namespace Umbraco.Web.Mvc
// filter / add preview banner
if (Response.ContentType.InvariantEquals("text/html")) // ASP.NET default value
{
if (UmbracoContext.Current.IsDebug || UmbracoContext.Current.InPreviewMode)
if (Current.UmbracoContext.IsDebug || Current.UmbracoContext.InPreviewMode)
{
var text = value.ToString();
var pos = text.IndexOf("</body>", StringComparison.InvariantCultureIgnoreCase);
@@ -215,13 +215,13 @@ namespace Umbraco.Web.Mvc
{
string markupToInject;
if (UmbracoContext.Current.InPreviewMode)
if (Current.UmbracoContext.InPreviewMode)
{
// creating previewBadge markup
markupToInject =
string.Format(Current.Configs.Settings().Content.PreviewBadge,
IOHelper.ResolveUrl(SystemDirectories.Umbraco),
Server.UrlEncode(UmbracoContext.Current.HttpContext.Request.Url?.PathAndQuery));
Server.UrlEncode(Current.UmbracoContext.HttpContext.Request.Url?.PathAndQuery));
}
else
{

View File

@@ -40,7 +40,7 @@ namespace Umbraco.Web.Mvc
/// </remarks>
protected virtual UmbracoContext GetUmbracoContext(RequestContext requestContext)
{
return UmbracoContext.Current;
return Composing.Current.UmbracoContext;
}
public IHttpHandler GetHttpHandler(RequestContext requestContext)

View File

@@ -4,6 +4,7 @@ using HeyRed.MarkdownSharp;
using Umbraco.Core;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Web.Composing;
using Umbraco.Web.Templates;
namespace Umbraco.Web.PropertyEditors.ValueConverters
@@ -26,7 +27,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
var sourceString = source.ToString();
// ensures string is parsed for {localLink} and urls are resolved correctly
sourceString = TemplateUtilities.ParseInternalLinks(sourceString, preview, UmbracoContext.Current);
sourceString = TemplateUtilities.ParseInternalLinks(sourceString, preview, Current.UmbracoContext);
sourceString = TemplateUtilities.ResolveUrlsFromTextString(sourceString);
return sourceString;

View File

@@ -2,6 +2,7 @@
using Umbraco.Core;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Web.Composing;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.Security;
@@ -44,7 +45,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
if (source == null)
return null;
if (UmbracoContext.Current != null)
if (Current.UmbracoContext != null)
{
IPublishedContent member;
if (source is int id)

View File

@@ -9,6 +9,7 @@ using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.PropertyEditors.ValueConverters;
using Umbraco.Core.Services;
using Umbraco.Web.Composing;
using Umbraco.Web.PublishedCache;
namespace Umbraco.Web.PropertyEditors.ValueConverters
@@ -67,7 +68,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
}
// TODO: Inject an UmbracoHelper and create a GetUmbracoHelper method based on either injected or singleton
if (UmbracoContext.Current != null)
if (Current.UmbracoContext != null)
{
if (propertyType.EditorAlias.Equals(Constants.PropertyEditors.Aliases.MultiNodeTreePicker))
{

View File

@@ -9,6 +9,7 @@ using System.Linq;
using HtmlAgilityPack;
using Umbraco.Core.Cache;
using Umbraco.Core.Services;
using Umbraco.Web.Composing;
using Umbraco.Web.Macros;
namespace Umbraco.Web.PropertyEditors.ValueConverters
@@ -72,7 +73,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
var sourceString = source.ToString();
// ensures string is parsed for {localLink} and urls are resolved correctly
sourceString = TemplateUtilities.ParseInternalLinks(sourceString, preview, UmbracoContext.Current);
sourceString = TemplateUtilities.ParseInternalLinks(sourceString, preview, Current.UmbracoContext);
sourceString = TemplateUtilities.ResolveUrlsFromTextString(sourceString);
// ensure string is parsed for macros and macros are executed correctly

View File

@@ -3,6 +3,7 @@ using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Web.Composing;
using Umbraco.Web.Templates;
namespace Umbraco.Web.PropertyEditors.ValueConverters
@@ -31,7 +32,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
var sourceString = source.ToString();
// ensures string is parsed for {localLink} and urls are resolved correctly
sourceString = TemplateUtilities.ParseInternalLinks(sourceString, preview, UmbracoContext.Current);
sourceString = TemplateUtilities.ParseInternalLinks(sourceString, preview, Current.UmbracoContext);
sourceString = TemplateUtilities.ResolveUrlsFromTextString(sourceString);
return sourceString;

View File

@@ -8,7 +8,7 @@ namespace Umbraco.Web.PublishedCache
/// </summary>
/// <remarks>A published snapshot is a point-in-time capture of the current state of
/// everything that is "published".</remarks>
public interface IPublishedSnapshot
public interface IPublishedSnapshot : IDisposable
{
/// <summary>
/// Gets the <see cref="IPublishedContentCache"/>.

View File

@@ -69,7 +69,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
return new ForcedPreviewObject(this, preview, callback);
}
private class ForcedPreviewObject : DisposableObject
private class ForcedPreviewObject : DisposableObjectSlim
{
private readonly PublishedSnapshot _publishedSnapshot;
private readonly bool _origPreview;

View File

@@ -46,11 +46,11 @@ namespace Umbraco.Web
switch (content.ItemType)
{
case PublishedItemType.Content:
if (UmbracoContext.Current == null)
throw new InvalidOperationException("Cannot resolve a Url for a content item when UmbracoContext.Current is null.");
if (UmbracoContext.Current.UrlProvider == null)
throw new InvalidOperationException("Cannot resolve a Url for a content item when UmbracoContext.Current.UrlProvider is null.");
return UmbracoContext.Current.UrlProvider.GetUrl(content.Id, true);
if (Current.UmbracoContext == null)
throw new InvalidOperationException("Cannot resolve a Url for a content item when Current.UmbracoContext is null.");
if (Current.UmbracoContext.UrlProvider == null)
throw new InvalidOperationException("Cannot resolve a Url for a content item when Current.UmbracoContext.UrlProvider is null.");
return Current.UmbracoContext.UrlProvider.GetUrl(content.Id, true);
case PublishedItemType.Media:
throw new NotSupportedException("AbsoluteUrl is not supported for media types.");
default:
@@ -267,7 +267,7 @@ namespace Umbraco.Web
.And()
.ManagedQuery(term);
return query.Execute().ToPublishedSearchResults(UmbracoContext.Current.ContentCache);
return query.Execute().ToPublishedSearchResults(Current.UmbracoContext.ContentCache);
}
public static IEnumerable<PublishedSearchResult> SearchChildren(this IPublishedContent content, string term, string indexName = null)
@@ -288,7 +288,7 @@ namespace Umbraco.Web
.And()
.ManagedQuery(term);
return query.Execute().ToPublishedSearchResults(UmbracoContext.Current.ContentCache);
return query.Execute().ToPublishedSearchResults(Current.UmbracoContext.ContentCache);
}
#endregion

View File

@@ -1,4 +1,5 @@
using System.Web;
using Umbraco.Web.Composing;
namespace Umbraco.Web.Routing
{
@@ -28,7 +29,7 @@ namespace Umbraco.Web.Routing
response.Clear();
var frequest = UmbracoContext.Current.PublishedRequest;
var frequest = Current.UmbracoContext.PublishedRequest;
var reason = "Cannot render the page at url '{0}'.";
if (frequest.HasPublishedContent == false)
reason = "No umbraco document matches the url '{0}'.";
@@ -37,7 +38,7 @@ namespace Umbraco.Web.Routing
response.Write("<html><body><h1>Page not found</h1>");
response.Write("<h3>");
response.Write(string.Format(reason, HttpUtility.HtmlEncode(UmbracoContext.Current.OriginalRequestUrl.PathAndQuery)));
response.Write(string.Format(reason, HttpUtility.HtmlEncode(Current.UmbracoContext.OriginalRequestUrl.PathAndQuery)));
response.Write("</h3>");
if (string.IsNullOrWhiteSpace(_message) == false)
response.Write("<p>" + _message + "</p>");

View File

@@ -38,9 +38,9 @@ namespace Umbraco.Web.Routing
{
get
{
var oldRoutes = (Dictionary<ContentIdAndCulture, ContentKeyAndOldRoute>) UmbracoContext.Current.HttpContext.Items[ContextKey3];
var oldRoutes = (Dictionary<ContentIdAndCulture, ContentKeyAndOldRoute>) Current.UmbracoContext.HttpContext.Items[ContextKey3];
if (oldRoutes == null)
UmbracoContext.Current.HttpContext.Items[ContextKey3] = oldRoutes = new Dictionary<ContentIdAndCulture, ContentKeyAndOldRoute>();
Current.UmbracoContext.HttpContext.Items[ContextKey3] = oldRoutes = new Dictionary<ContentIdAndCulture, ContentKeyAndOldRoute>();
return oldRoutes;
}
}
@@ -58,27 +58,27 @@ namespace Umbraco.Web.Routing
private static bool LockedEvents
{
get => Moving && UmbracoContext.Current.HttpContext.Items[ContextKey2] != null;
get => Moving && Current.UmbracoContext.HttpContext.Items[ContextKey2] != null;
set
{
if (Moving && value)
UmbracoContext.Current.HttpContext.Items[ContextKey2] = true;
Current.UmbracoContext.HttpContext.Items[ContextKey2] = true;
else
UmbracoContext.Current.HttpContext.Items.Remove(ContextKey2);
Current.UmbracoContext.HttpContext.Items.Remove(ContextKey2);
}
}
private static bool Moving
{
get => UmbracoContext.Current.HttpContext.Items[ContextKey1] != null;
get => Current.UmbracoContext.HttpContext.Items[ContextKey1] != null;
set
{
if (value)
UmbracoContext.Current.HttpContext.Items[ContextKey1] = true;
Current.UmbracoContext.HttpContext.Items[ContextKey1] = true;
else
{
UmbracoContext.Current.HttpContext.Items.Remove(ContextKey1);
UmbracoContext.Current.HttpContext.Items.Remove(ContextKey2);
Current.UmbracoContext.HttpContext.Items.Remove(ContextKey1);
Current.UmbracoContext.HttpContext.Items.Remove(ContextKey2);
}
}
}
@@ -164,7 +164,7 @@ namespace Umbraco.Web.Routing
{
if (LockedEvents) return;
var contentCache = UmbracoContext.Current.ContentCache;
var contentCache = Current.UmbracoContext.ContentCache;
foreach (var entity in args.PublishedEntities)
{
var entityContent = contentCache.GetById(entity.Id);
@@ -205,7 +205,7 @@ namespace Umbraco.Web.Routing
private static void CreateRedirect(int contentId, string culture, Guid contentKey, string oldRoute)
{
var contentCache = UmbracoContext.Current.ContentCache;
var contentCache = Current.UmbracoContext.ContentCache;
var newRoute = contentCache.GetRouteById(contentId, culture);
if (IsNotRoute(newRoute) || oldRoute == newRoute) return;
var redirectUrlService = Current.Services.RedirectUrlService;

View File

@@ -6,6 +6,7 @@ using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Services;
using Umbraco.Web.Composing;
namespace Umbraco.Web.Routing
{
@@ -210,7 +211,7 @@ namespace Umbraco.Web.Routing
var provider = _urlProviders.OfType<DefaultUrlProvider>().FirstOrDefault();
var url = provider == null
? route // what else?
: provider.GetUrlFromRoute(route, UmbracoContext.Current, id, _umbracoContext.CleanedUmbracoUrl, Mode, culture)?.Text;
: provider.GetUrlFromRoute(route, Current.UmbracoContext, id, _umbracoContext.CleanedUmbracoUrl, Mode, culture)?.Text;
return url ?? "#";
}

View File

@@ -68,7 +68,7 @@ namespace Umbraco.Web.Runtime
}
public void Initialize()
{
{
// setup mvc and webapi services
SetupMvcAndWebApi();
@@ -87,23 +87,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

@@ -76,6 +76,9 @@ namespace Umbraco.Web.Runtime
// let's use an hybrid accessor that can fall back to a ThreadStatic context.
composition.RegisterUnique<IUmbracoContextAccessor, HybridUmbracoContextAccessor>();
// register the umbraco context factory
composition.RegisterUnique<IUmbracoContextFactory, UmbracoContextFactory>();
// register a per-request HttpContextBase object
// is per-request so only one wrapper is created per request
composition.Register<HttpContextBase>(factory => new HttpContextWrapper(factory.GetInstance<IHttpContextAccessor>().HttpContext), Lifetime.Request);

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

@@ -23,6 +23,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;
@@ -37,13 +38,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;
@@ -113,11 +115,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

@@ -703,7 +703,7 @@ namespace Umbraco.Web.Security
/// <returns></returns>
public virtual Attempt<PasswordChangedModel> ChangePassword(string username, ChangingPasswordModel passwordModel, MembershipProvider membershipProvider)
{
var passwordChanger = new PasswordChanger(_logger, _userService, Web.Composing.Current.UmbracoContext.HttpContext);
var passwordChanger = new PasswordChanger(_logger, _userService, UmbracoContext.HttpContext);
return passwordChanger.ChangePasswordWithMembershipProvider(username, passwordModel, membershipProvider);
}

View File

@@ -138,6 +138,7 @@
<Compile Include="Editors\KeepAliveController.cs" />
<Compile Include="Editors\MacrosController.cs" />
<Compile Include="Editors\RelationTypeController.cs" />
<Compile Include="IUmbracoContextFactory.cs" />
<Compile Include="Install\ChangesMonitor.cs" />
<Compile Include="Logging\WebProfiler.cs" />
<Compile Include="Logging\WebProfilerComponent.cs" />
@@ -208,6 +209,8 @@
<Compile Include="Models\Link.cs" />
<Compile Include="Models\LinkType.cs" />
<Compile Include="Models\TemplateQuery\OperatorFactory.cs" />
<Compile Include="UmbracoContextFactory.cs" />
<Compile Include="UmbracoContextReference.cs" />
<Compile Include="WebApi\Filters\OnlyLocalRequestsAttribute.cs" />
<Compile Include="PropertyEditors\MultiUrlPickerConfiguration.cs" />
<Compile Include="PropertyEditors\MultiUrlPickerConfigurationEditor.cs" />

View File

@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Web.Hosting;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Composing;
@@ -18,7 +16,7 @@ namespace Umbraco.Web
/// <summary>
/// Class that encapsulates Umbraco information of a specific HTTP request
/// </summary>
public class UmbracoContext : DisposableObject, IDisposeOnRequestEnd
public class UmbracoContext : DisposableObjectSlim, IDisposeOnRequestEnd
{
private readonly IGlobalSettings _globalSettings;
private readonly Lazy<IPublishedSnapshot> _publishedSnapshot;
@@ -26,102 +24,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,14 +74,6 @@ namespace Umbraco.Web
UrlProvider = new UrlProvider(this, umbracoSettings.WebRouting, urlProviders, variationContextAccessor);
}
#endregion
/// <summary>
/// Gets the current Umbraco Context.
/// </summary>
// note: obsolete, use Current.UmbracoContext... then obsolete Current too, and inject!
public static UmbracoContext Current => Composing.Current.UmbracoContext;
/// <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.
@@ -281,7 +175,7 @@ namespace Umbraco.Web
|| string.IsNullOrEmpty(request["umbdebug"]) == false);
}
}
/// <summary>
/// Determines whether the current user is in a preview mode and browsing the site (ie. not in the admin UI)
/// </summary>
@@ -345,15 +239,11 @@ 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
if (_publishedSnapshot.IsValueCreated)
_publishedSnapshot.Value.DisposeIfDisposable();
_publishedSnapshot.Value.Dispose();
}
}
}

View File

@@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Web;
using System.Web.Hosting;
using Umbraco.Core.Configuration;
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.Security;
namespace Umbraco.Web
{
/// <summary>
/// Creates and manages <see cref="UmbracoContext"/> instances.
/// </summary>
public class UmbracoContextFactory : IUmbracoContextFactory
{
private static readonly NullWriter NullWriterInstance = new NullWriter();
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;
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoContextFactory"/> class.
/// </summary>
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));
}
private 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);
}
/// <inheritdoc />
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("null.aspx", "", NullWriterInstance)));
var umbracoContext = CreateUmbracoContext(httpContext);
_umbracoContextAccessor.UmbracoContext = umbracoContext;
return new UmbracoContextReference(umbracoContext, true, _umbracoContextAccessor);
}
// dummy TextWriter that does not write
private class NullWriter : TextWriter
{
public override Encoding Encoding => Encoding.UTF8;
}
}
}

View File

@@ -0,0 +1,60 @@
using System;
namespace Umbraco.Web
{
/// <summary>
/// Represents a reference to an <see cref="UmbracoContext"/> instance.
/// </summary>
/// <remarks>
/// <para>A reference points to an <see cref="UmbracoContext"/> and it may own it (when it
/// is a root reference) or just reference it. A reference must be disposed after it has
/// been used. Disposing does nothing if the reference is not a root reference. Otherwise,
/// it disposes the <see cref="UmbracoContext"/> and clears the
/// <see cref="IUmbracoContextAccessor"/>.</para>
/// </remarks>
public class UmbracoContextReference : IDisposable //fixme - should we inherit from DisposableObjectSlim?
{
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private bool _disposed;
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoContextReference"/> class.
/// </summary>
internal UmbracoContextReference(UmbracoContext umbracoContext, bool isRoot, IUmbracoContextAccessor umbracoContextAccessor)
{
UmbracoContext = umbracoContext;
IsRoot = isRoot;
_umbracoContextAccessor = umbracoContextAccessor;
}
/// <summary>
/// Gets the <see cref="UmbracoContext"/>.
/// </summary>
public UmbracoContext UmbracoContext { get; }
/// <summary>
/// Gets a value indicating whether the reference is a root reference.
/// </summary>
/// <remarks>
/// <para></para>
/// </remarks>
public bool IsRoot { get; }
/// <inheritdoc />
public void Dispose()
{
if (_disposed)
return;
_disposed = true;
if (IsRoot)
{
UmbracoContext.Dispose();
_umbracoContextAccessor.UmbracoContext = null;
}
GC.SuppressFinalize(this);
}
}
}

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>
@@ -124,10 +119,10 @@ namespace Umbraco.Web
if (httpContext.Request.Url.IsClientSideRequest())
return;
if (UmbracoContext.Current == null)
throw new InvalidOperationException("The UmbracoContext.Current is null, ProcessRequest cannot proceed unless there is a current UmbracoContext");
if (Current.UmbracoContext == null)
throw new InvalidOperationException("The Current.UmbracoContext is null, ProcessRequest cannot proceed unless there is a current UmbracoContext");
var umbracoContext = UmbracoContext.Current;
var umbracoContext = Current.UmbracoContext;
// re-write for the default back office path
if (httpContext.Request.Url.IsDefaultBackOfficeRequest(_globalSettings))
@@ -491,14 +486,14 @@ namespace Umbraco.Web
{
var httpContext = ((HttpApplication) sender).Context;
if (UmbracoContext.Current != null && UmbracoContext.Current.IsFrontEndUmbracoRequest)
if (Current.UmbracoContext != null && Current.UmbracoContext.IsFrontEndUmbracoRequest)
{
LogHttpRequest.TryGetCurrentHttpRequestId(out var httpRequestId);
_logger.Verbose<UmbracoModule>("End Request [{HttpRequestId}]: {RequestUrl} ({RequestDuration}ms)", httpRequestId, httpContext.Request.Url, DateTime.Now.Subtract(UmbracoContext.Current.ObjectCreated).TotalMilliseconds);
_logger.Verbose<UmbracoModule>("End Request [{HttpRequestId}]: {RequestUrl} ({RequestDuration}ms)", httpRequestId, httpContext.Request.Url, DateTime.Now.Subtract(Current.UmbracoContext.ObjectCreated).TotalMilliseconds);
}
UmbracoModule.OnEndRequest(this, new UmbracoRequestEventArgs(UmbracoContext.Current, new HttpContextWrapper(httpContext)));
UmbracoModule.OnEndRequest(this, new UmbracoRequestEventArgs(Current.UmbracoContext, new HttpContextWrapper(httpContext)));
DisposeHttpContextItems(httpContext);
};

View File

@@ -296,7 +296,7 @@ namespace Umbraco.Web
var encryptedRoute = UmbracoHelper.CreateEncryptedRouteString(controllerName, action, area, additionalRouteVals);
var result = UmbracoContext.Current.OriginalRequestUrl.AbsolutePath.EnsureEndsWith('?') + "ufprt=" + encryptedRoute;
var result = Current.UmbracoContext.OriginalRequestUrl.AbsolutePath.EnsureEndsWith('?') + "ufprt=" + encryptedRoute;
return result;
}
@@ -339,7 +339,7 @@ namespace Umbraco.Web
var encryptedRoute = UmbracoHelper.CreateEncryptedRouteString(metaData.ControllerName, action, area, additionalRouteVals);
var result = UmbracoContext.Current.OriginalRequestUrl.AbsolutePath.EnsureEndsWith('?') + "ufprt=" + encryptedRoute;
var result = Current.UmbracoContext.OriginalRequestUrl.AbsolutePath.EnsureEndsWith('?') + "ufprt=" + encryptedRoute;
return result;
}

View File

@@ -18,7 +18,7 @@ namespace Umbraco.Web.WebApi.Filters
{
if (context.Response == null) return;
if (context.Request.Method == HttpMethod.Get) return;
if (UmbracoContext.Current == null) return;
if (Current.UmbracoContext == null) return;
var obj = context.Response.Content as ObjectContent;
if (obj == null) return;

View File

@@ -2,6 +2,7 @@
using System.Web.Http.Filters;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Web.Composing;
namespace Umbraco.Web.WebApi.Filters
{
@@ -53,7 +54,7 @@ namespace Umbraco.Web.WebApi.Filters
throw new InvalidOperationException("No argument found for the current action with the name: " + _userIdParameter);
}
var user = UmbracoContext.Current.Security.CurrentUser;
var user = Current.UmbracoContext.Security.CurrentUser;
if (user == null) return;
var userId = GetUserIdFromParameter(actionContext.ActionArguments[_userIdParameter]);

View File

@@ -61,7 +61,7 @@ namespace Umbraco.Web.WebApi.Filters
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (UmbracoContext.Current.Security.CurrentUser == null)
if (Current.UmbracoContext.Security.CurrentUser == null)
{
//not logged in
throw new HttpResponseException(System.Net.HttpStatusCode.Unauthorized);

View File

@@ -80,7 +80,7 @@ namespace Umbraco.Web.WebApi.Filters
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (UmbracoContext.Current.Security.CurrentUser == null)
if (Current.UmbracoContext.Security.CurrentUser == null)
{
throw new HttpResponseException(System.Net.HttpStatusCode.Unauthorized);
}
@@ -118,7 +118,7 @@ namespace Umbraco.Web.WebApi.Filters
if (MediaController.CheckPermissions(
actionContext.Request.Properties,
UmbracoContext.Current.Security.CurrentUser,
Current.UmbracoContext.Security.CurrentUser,
Current.Services.MediaService,
Current.Services.EntityService,
nodeId))

View File

@@ -48,7 +48,7 @@ namespace Umbraco.Web.WebApi.Filters
{
if (actionExecutedContext.Response == null) return;
var user = UmbracoContext.Current.Security.CurrentUser;
var user = Composing.Current.UmbracoContext.Security.CurrentUser;
if (user == null) return;
var objectContent = actionExecutedContext.Response.Content as ObjectContent;

View File

@@ -2,6 +2,7 @@
using System.Net.Http;
using System.Web.Http.Filters;
using Umbraco.Core;
using Umbraco.Web.Composing;
using Umbraco.Web.Editors;
using Umbraco.Web.Models.ContentEditing;
@@ -16,7 +17,7 @@ namespace Umbraco.Web.WebApi.Filters
{
if (actionExecutedContext.Response == null) return;
var user = UmbracoContext.Current.Security.CurrentUser;
var user = Current.UmbracoContext.Security.CurrentUser;
if (user == null) return;
if (actionExecutedContext.Response.Content is ObjectContent objectContent)
@@ -27,7 +28,7 @@ namespace Umbraco.Web.WebApi.Filters
{
var args = new EditorModelEventArgs(
model,
UmbracoContext.Current);
Current.UmbracoContext);
EditorModelEventManager.EmitEvent(actionExecutedContext, args);
objectContent.Value = args.Model;
}