diff --git a/src/Umbraco.Core/Events/UmbracoRequestBegin.cs b/src/Umbraco.Core/Events/UmbracoRequestBegin.cs
index ffb55938b3..00eb41df96 100644
--- a/src/Umbraco.Core/Events/UmbracoRequestBegin.cs
+++ b/src/Umbraco.Core/Events/UmbracoRequestBegin.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Umbraco.
+// Copyright (c) Umbraco.
// See LICENSE for more details.
using Umbraco.Cms.Core.Web;
diff --git a/src/Umbraco.Core/Events/UmbracoRoutedRequest.cs b/src/Umbraco.Core/Events/UmbracoRoutedRequest.cs
new file mode 100644
index 0000000000..dd2b4d0d58
--- /dev/null
+++ b/src/Umbraco.Core/Events/UmbracoRoutedRequest.cs
@@ -0,0 +1,33 @@
+// Copyright (c) Umbraco.
+// See LICENSE for more details.
+
+using System;
+using Umbraco.Cms.Core.Web;
+using Umbraco.Extensions;
+
+namespace Umbraco.Cms.Core.Events
+{
+ ///
+ /// Notification raised when Umbraco routes a front-end request.
+ ///
+ public class UmbracoRoutedRequest : INotification
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public UmbracoRoutedRequest(IUmbracoContext umbracoContext)
+ {
+ if (!umbracoContext.IsFrontEndUmbracoRequest())
+ {
+ throw new InvalidOperationException($"{nameof(UmbracoRoutedRequest)} is only valid for Umbraco front-end requests");
+ }
+
+ UmbracoContext = umbracoContext;
+ }
+
+ ///
+ /// Gets the
+ ///
+ public IUmbracoContext UmbracoContext { get; }
+ }
+}
diff --git a/src/Umbraco.Core/HybridAccessorBase.cs b/src/Umbraco.Core/HybridAccessorBase.cs
index ae3b4471e9..51a51e0d01 100644
--- a/src/Umbraco.Core/HybridAccessorBase.cs
+++ b/src/Umbraco.Core/HybridAccessorBase.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Scoping;
@@ -18,12 +18,12 @@ namespace Umbraco.Cms.Core
{
private readonly IRequestCache _requestCache;
- // ReSharper disable StaticMemberInGenericType
- private static readonly object Locker = new object();
- private static bool _registered;
- // ReSharper restore StaticMemberInGenericType
+ private readonly object _locker = new object();
+ private readonly bool _registered;
- protected abstract string ItemKey { get; }
+ private string _itemKey;
+
+ protected string ItemKey => _itemKey ??= GetType().FullName;
// read
// http://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html
@@ -43,20 +43,21 @@ namespace Umbraco.Cms.Core
private T NonContextValue
{
get => CallContext.GetData(ItemKey);
- set
- {
- CallContext.SetData(ItemKey, value);
- }
+ set => CallContext.SetData(ItemKey, value);
}
protected HybridAccessorBase(IRequestCache requestCache)
{
_requestCache = requestCache ?? throw new ArgumentNullException(nameof(requestCache));
- lock (Locker)
+ lock (_locker)
{
// register the itemKey once with SafeCallContext
- if (_registered) return;
+ if (_registered)
+ {
+ return;
+ }
+
_registered = true;
}
@@ -64,13 +65,20 @@ namespace Umbraco.Cms.Core
var itemKey = ItemKey; // virtual
SafeCallContext.Register(() =>
{
- var value = CallContext.GetData(itemKey);
+ T value = CallContext.GetData(itemKey);
return value;
}, o =>
{
- if (o == null) return;
- var value = o as T;
- if (value == null) throw new ArgumentException($"Expected type {typeof(T).FullName}, got {o.GetType().FullName}", nameof(o));
+ if (o == null)
+ {
+ return;
+ }
+
+ if (o is not T value)
+ {
+ throw new ArgumentException($"Expected type {typeof(T).FullName}, got {o.GetType().FullName}", nameof(o));
+ }
+
CallContext.SetData(itemKey, value);
});
}
@@ -93,9 +101,13 @@ namespace Umbraco.Cms.Core
NonContextValue = value;
}
else if (value == null)
+ {
_requestCache.Remove(ItemKey);
+ }
else
+ {
_requestCache.Set(ItemKey, value);
+ }
}
}
}
diff --git a/src/Umbraco.Core/HybridEventMessagesAccessor.cs b/src/Umbraco.Core/HybridEventMessagesAccessor.cs
index 6f4d33a307..df6a34aae8 100644
--- a/src/Umbraco.Core/HybridEventMessagesAccessor.cs
+++ b/src/Umbraco.Core/HybridEventMessagesAccessor.cs
@@ -1,12 +1,10 @@
-using Umbraco.Cms.Core.Cache;
+using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Events;
namespace Umbraco.Cms.Core
{
public class HybridEventMessagesAccessor : HybridAccessorBase, IEventMessagesAccessor
{
- protected override string ItemKey => "Umbraco.Core.Events.HybridEventMessagesAccessor";
-
public HybridEventMessagesAccessor(IRequestCache requestCache)
: base(requestCache)
{ }
diff --git a/src/Umbraco.Core/Models/PublishedContent/HybridVariationContextAccessor.cs b/src/Umbraco.Core/Models/PublishedContent/HybridVariationContextAccessor.cs
index c412a4de3a..9c50b60ac1 100644
--- a/src/Umbraco.Core/Models/PublishedContent/HybridVariationContextAccessor.cs
+++ b/src/Umbraco.Core/Models/PublishedContent/HybridVariationContextAccessor.cs
@@ -1,4 +1,4 @@
-using Umbraco.Cms.Core.Cache;
+using Umbraco.Cms.Core.Cache;
namespace Umbraco.Cms.Core.Models.PublishedContent
{
@@ -11,9 +11,6 @@ namespace Umbraco.Cms.Core.Models.PublishedContent
: base(requestCache)
{ }
- ///
- protected override string ItemKey => "Umbraco.Web.HybridVariationContextAccessor";
-
///
/// Gets or sets the object.
///
diff --git a/src/Umbraco.Core/Security/HybridBackofficeSecurityAccessor.cs b/src/Umbraco.Core/Security/HybridBackofficeSecurityAccessor.cs
index 990715ce39..924f0a31a6 100644
--- a/src/Umbraco.Core/Security/HybridBackofficeSecurityAccessor.cs
+++ b/src/Umbraco.Core/Security/HybridBackofficeSecurityAccessor.cs
@@ -1,4 +1,4 @@
-using Umbraco.Cms.Core.Cache;
+using Umbraco.Cms.Core.Cache;
namespace Umbraco.Cms.Core.Security
{
@@ -11,9 +11,6 @@ namespace Umbraco.Cms.Core.Security
: base(requestCache)
{ }
- ///
- protected override string ItemKey => "Umbraco.Web.HybridBackofficeSecurityAccessor";
-
///
/// Gets or sets the object.
///
diff --git a/src/Umbraco.Core/Security/HybridUmbracoWebsiteSecurityAccessor.cs b/src/Umbraco.Core/Security/HybridUmbracoWebsiteSecurityAccessor.cs
index cb986588d3..3145f400d1 100644
--- a/src/Umbraco.Core/Security/HybridUmbracoWebsiteSecurityAccessor.cs
+++ b/src/Umbraco.Core/Security/HybridUmbracoWebsiteSecurityAccessor.cs
@@ -1,4 +1,4 @@
-using Umbraco.Cms.Core.Cache;
+using Umbraco.Cms.Core.Cache;
namespace Umbraco.Cms.Core.Security
{
@@ -12,9 +12,6 @@ namespace Umbraco.Cms.Core.Security
: base(requestCache)
{ }
- ///
- protected override string ItemKey => "Umbraco.Web.HybridUmbracoWebsiteSecurityAccessor";
-
///
/// Gets or sets the object.
///
diff --git a/src/Umbraco.Core/IBackofficeSecurityFactory.cs b/src/Umbraco.Core/Security/IBackOfficeSecurityFactory.cs
similarity index 90%
rename from src/Umbraco.Core/IBackofficeSecurityFactory.cs
rename to src/Umbraco.Core/Security/IBackOfficeSecurityFactory.cs
index ac7c875f16..ee553e85e6 100644
--- a/src/Umbraco.Core/IBackofficeSecurityFactory.cs
+++ b/src/Umbraco.Core/Security/IBackOfficeSecurityFactory.cs
@@ -1,4 +1,4 @@
-namespace Umbraco.Cms.Core
+namespace Umbraco.Cms.Core.Security
{
///
/// Creates and manages instances.
diff --git a/src/Umbraco.Core/Security/IUmbracoWebsiteSecurity.cs b/src/Umbraco.Core/Security/IUmbracoWebsiteSecurity.cs
index 86dbb9683e..10fb9b5f2c 100644
--- a/src/Umbraco.Core/Security/IUmbracoWebsiteSecurity.cs
+++ b/src/Umbraco.Core/Security/IUmbracoWebsiteSecurity.cs
@@ -1,9 +1,10 @@
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Threading.Tasks;
using Umbraco.Cms.Core.Models.Security;
namespace Umbraco.Cms.Core.Security
{
+ // TODO: I think we can kill this whole thing, the logic can just be in the controllers
public interface IUmbracoWebsiteSecurity
{
///
@@ -35,18 +36,10 @@ namespace Umbraco.Cms.Core.Security
/// Result of update profile operation.
Task UpdateMemberProfileAsync(ProfileModel model);
- ///
- /// A helper method to perform the validation and logging in of a member.
- ///
- /// The username.
- /// The password.
- /// Result of login operation.
+ // TODO: Kill this, we will just use the MemberManager / MemberSignInManager
Task LoginAsync(string username, string password);
- ///
- /// Check if a member is logged in
- ///
- /// True if logged in, false if not.
+ // TODO: Kill this, we will just use the MemberManager
bool IsLoggedIn();
///
@@ -55,9 +48,7 @@ namespace Umbraco.Cms.Core.Security
/// Instance of
Task GetCurrentLoginStatusAsync();
- ///
- /// Logs out the current member.
- ///
+ // TODO: Kill this, we will just use the MemberManager
Task LogOutAsync();
///
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 3f7c1064b2..e4518dc51c 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -2,11 +2,7 @@
netstandard2.0
- 8
Umbraco.Cms.Core
- 0.5.0
- 0.5.0
- 0.5.0
Umbraco CMS
Umbraco.Cms.Core
Umbraco CMS Core
diff --git a/src/Umbraco.Core/Web/HybridUmbracoContextAccessor.cs b/src/Umbraco.Core/Web/HybridUmbracoContextAccessor.cs
index a266c07769..503bb25b57 100644
--- a/src/Umbraco.Core/Web/HybridUmbracoContextAccessor.cs
+++ b/src/Umbraco.Core/Web/HybridUmbracoContextAccessor.cs
@@ -1,4 +1,4 @@
-using Umbraco.Cms.Core.Cache;
+using Umbraco.Cms.Core.Cache;
namespace Umbraco.Cms.Core.Web
{
@@ -14,9 +14,6 @@ namespace Umbraco.Cms.Core.Web
: base(requestCache)
{ }
- ///
- protected override string ItemKey => "Umbraco.Web.HybridUmbracoContextAccessor";
-
///
/// Gets or sets the object.
///
diff --git a/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs b/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs
index bc81bfabcf..0fc1809250 100644
--- a/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs
+++ b/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs
@@ -106,7 +106,11 @@ namespace Umbraco.Cms.Infrastructure.HostedServices
// - batched messenger should not depend on a current HttpContext
// 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)
- //
+
+ // TODO: This dependency chain is broken and needs to be fixed.
+ // This is required to be called before EnsureUmbracoContext else the UmbracoContext's IBackOfficeSecurity instance is null
+ // This is a very ugly Temporal Coupling which also means that developers can no longer just use IUmbracoContextFactory the
+ // way it was intended.
_backofficeSecurityFactory.EnsureBackOfficeSecurity();
using UmbracoContextReference contextReference = _umbracoContextFactory.EnsureUmbracoContext();
try
diff --git a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs
index 22fa172874..e8f5072e18 100644
--- a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs
+++ b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs
@@ -80,6 +80,7 @@ _hostingEnvironment = hostingEnvironment;
{
db = _dbFactory.CreateDatabase();
+
_hasTable = db.HasTable(Cms.Core.Constants.DatabaseSchema.Tables.KeyValue);
if (!_hasTable)
{
diff --git a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj
index 0b3e4f909c..43a1c53e43 100644
--- a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj
+++ b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj
@@ -2,7 +2,6 @@
netstandard2.0
- 8
Umbraco.Cms.Infrastructure
Umbraco.Cms.Infrastructure
Umbraco CMS Infrastructure
diff --git a/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj b/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj
index f80e8669b4..5c3ebd1a4c 100644
--- a/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj
+++ b/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj
@@ -2,7 +2,6 @@
netstandard2.0
- latest
Umbraco.Cms.Tests.Common
Umbraco.Cms.Tests
Umbraco CMS Test Tools
diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs
index caed95ae52..dbb2adef89 100644
--- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs
+++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs
@@ -18,6 +18,7 @@ using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;
+using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Tests.Common.Testing;
using Umbraco.Cms.Tests.Integration.DependencyInjection;
@@ -26,7 +27,6 @@ using Umbraco.Cms.Web.BackOffice.Controllers;
using Umbraco.Cms.Web.Common.Controllers;
using Umbraco.Cms.Web.Website.Controllers;
using Umbraco.Extensions;
-using Constants = Umbraco.Cms.Core.Constants;
namespace Umbraco.Cms.Tests.Integration.TestServerTest
{
@@ -122,6 +122,10 @@ namespace Umbraco.Cms.Tests.Integration.TestServerTest
}
};
+ // TODO: This dependency chain is broken and needs to be fixed.
+ // This is required to be called before EnsureUmbracoContext else the UmbracoContext's IBackOfficeSecurity instance is null
+ // This is a very ugly Temporal Coupling which also means that developers can no longer just use IUmbracoContextFactory the
+ // way it was intended.
backofficeSecurityFactory.EnsureBackOfficeSecurity();
umbracoContextFactory.EnsureUmbracoContext();
diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs
index eab085f67e..133320b853 100644
--- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs
+++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs
@@ -25,6 +25,7 @@ using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Scoping;
+using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Core.Web;
@@ -37,7 +38,6 @@ using Umbraco.Cms.Tests.Integration.DependencyInjection;
using Umbraco.Cms.Tests.Integration.Extensions;
using Umbraco.Cms.Tests.Integration.Implementations;
using Umbraco.Extensions;
-using Constants = Umbraco.Cms.Core.Constants;
namespace Umbraco.Cms.Tests.Integration.Testing
{
diff --git a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj
index 18cc68996d..f45a7bc444 100644
--- a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj
+++ b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj
@@ -4,7 +4,6 @@
Exe
net5.0
false
- 8
Umbraco.Cms.Tests.Integration
diff --git a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs
index 5cf0dc7b28..91432f142e 100644
--- a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs
+++ b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs
@@ -11,12 +11,12 @@ using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
-using Umbraco.Cms.Core;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.ContentEditing;
using Umbraco.Cms.Core.PropertyEditors;
+using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs
index 62ee1fdd29..3ef434edab 100644
--- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs
+++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs
@@ -8,6 +8,7 @@ using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Runtime;
+using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Sync;
using Umbraco.Cms.Core.Web;
diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs
index 4d74ea6427..e8e8fec2e0 100644
--- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs
+++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs
@@ -13,6 +13,7 @@ using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
+using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
@@ -56,7 +57,8 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Website.Routing
routeValuesFactory ?? Mock.Of(),
filter ?? Mock.Of(x => x.IsDocumentRequest(It.IsAny()) == true),
Mock.Of(),
- Mock.Of());
+ Mock.Of(),
+ Mock.Of());
return transformer;
}
diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Security/UmbracoWebsiteSecurityTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Security/UmbracoWebsiteSecurityTests.cs
index 5e53486d11..badcaae8b5 100644
--- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Security/UmbracoWebsiteSecurityTests.cs
+++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Security/UmbracoWebsiteSecurityTests.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Umbraco.
+// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Linq;
@@ -13,7 +13,7 @@ using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Tests.Common.Builders;
-using Umbraco.Cms.Web.Website.Security;
+using Umbraco.Cms.Web.Common.Security;
using CoreConstants = Umbraco.Cms.Core.Constants;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Website.Security
diff --git a/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj b/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj
index cd80f15b92..667cceb8be 100644
--- a/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj
+++ b/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj
@@ -3,7 +3,6 @@
net5.0
Library
- latest
Umbraco.Cms.Web.BackOffice
Umbraco.Cms.Web.BackOffice
Umbraco CMS Back Office
diff --git a/src/Umbraco.Web.Common/Controllers/ProxyViewDataFeature.cs b/src/Umbraco.Web.Common/Controllers/ProxyViewDataFeature.cs
index f926ccbfaa..e44f3270fe 100644
--- a/src/Umbraco.Web.Common/Controllers/ProxyViewDataFeature.cs
+++ b/src/Umbraco.Web.Common/Controllers/ProxyViewDataFeature.cs
@@ -1,4 +1,4 @@
-using Microsoft.AspNetCore.Mvc.ViewFeatures;
+using Microsoft.AspNetCore.Mvc.ViewFeatures;
namespace Umbraco.Cms.Web.Common.Controllers
{
@@ -10,11 +10,20 @@ namespace Umbraco.Cms.Web.Common.Controllers
///
/// Initializes a new instance of the class.
///
- public ProxyViewDataFeature(ViewDataDictionary viewData) => ViewData = viewData;
+ public ProxyViewDataFeature(ViewDataDictionary viewData, ITempDataDictionary tempData)
+ {
+ ViewData = viewData;
+ TempData = tempData;
+ }
///
/// Gets the
///
public ViewDataDictionary ViewData { get; }
+
+ ///
+ /// Gets the
+ ///
+ public ITempDataDictionary TempData { get; }
}
}
diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs
index 9dd375c9af..6c11b91a95 100644
--- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs
+++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs
@@ -255,6 +255,7 @@ namespace Umbraco.Extensions
builder.Services.AddUnique();
builder.Services.AddUnique();
+ builder.Services.AddUnique();
builder.Services.AddUnique();
// register the umbraco context factory
@@ -262,6 +263,7 @@ namespace Umbraco.Extensions
builder.Services.AddUnique();
builder.Services.AddUnique();
builder.Services.AddUnique();
+ builder.AddNotificationHandler();
builder.Services.AddUnique();
var umbracoApiControllerTypes = builder.TypeLoader.GetUmbracoApiControllers().ToList();
diff --git a/src/Umbraco.Web.Common/Macros/MacroRenderer.cs b/src/Umbraco.Web.Common/Macros/MacroRenderer.cs
index f798199012..129936071c 100644
--- a/src/Umbraco.Web.Common/Macros/MacroRenderer.cs
+++ b/src/Umbraco.Web.Common/Macros/MacroRenderer.cs
@@ -37,6 +37,7 @@ namespace Umbraco.Cms.Web.Common.Macros
private readonly ISessionManager _sessionManager;
private readonly IRequestAccessor _requestAccessor;
private readonly IHttpContextAccessor _httpContextAccessor;
+ private readonly PartialViewMacroEngine _partialViewMacroEngine;
public MacroRenderer(
IProfilingLogger profilingLogger,
@@ -52,7 +53,8 @@ namespace Umbraco.Cms.Web.Common.Macros
IMemberUserKeyProvider memberUserKeyProvider,
ISessionManager sessionManager,
IRequestAccessor requestAccessor,
- IHttpContextAccessor httpContextAccessor)
+ IHttpContextAccessor httpContextAccessor,
+ PartialViewMacroEngine partialViewMacroEngine)
{
_profilingLogger = profilingLogger ?? throw new ArgumentNullException(nameof(profilingLogger));
_logger = logger;
@@ -68,6 +70,7 @@ namespace Umbraco.Cms.Web.Common.Macros
_sessionManager = sessionManager;
_requestAccessor = requestAccessor;
_httpContextAccessor = httpContextAccessor;
+ _partialViewMacroEngine = partialViewMacroEngine;
}
#region MacroContent cache
@@ -338,38 +341,27 @@ namespace Umbraco.Cms.Web.Common.Macros
private Attempt ExecuteMacroOfType(MacroModel model, IPublishedContent content)
{
if (model == null)
+ {
throw new ArgumentNullException(nameof(model));
+ }
// ensure that we are running against a published node (ie available in XML)
// that may not be the case if the macro is embedded in a RTE of an unpublished document
if (content == null)
+ {
return Attempt.Fail(new MacroContent { Text = "[macro failed (no content)]" });
+ }
- var textService = _textService;
return ExecuteMacroWithErrorWrapper(model,
$"Executing PartialView: MacroSource=\"{model.MacroSource}\".",
"Executed PartialView.",
- () => ExecutePartialView(model, content),
- () => textService.Localize("errors/macroErrorLoadingPartialView", new[] { model.MacroSource }));
+ () => _partialViewMacroEngine.Execute(model, content),
+ () => _textService.Localize("errors/macroErrorLoadingPartialView", new[] { model.MacroSource }));
}
- #endregion
-
- #region Execute engines
-
- ///
- /// Renders a PartialView Macro.
- ///
- /// The text output of the macro execution.
- private MacroContent ExecutePartialView(MacroModel macro, IPublishedContent content)
- {
- var engine = new PartialViewMacroEngine(_httpContextAccessor, _hostingEnvironment);
- return engine.Execute(macro, content);
- }
-
#endregion
#region Execution helpers
diff --git a/src/Umbraco.Web.Common/Macros/PartialViewMacroEngine.cs b/src/Umbraco.Web.Common/Macros/PartialViewMacroEngine.cs
index ef59c9f896..4cbc2d7648 100644
--- a/src/Umbraco.Web.Common/Macros/PartialViewMacroEngine.cs
+++ b/src/Umbraco.Web.Common/Macros/PartialViewMacroEngine.cs
@@ -16,6 +16,7 @@ using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.Macros;
using Umbraco.Cms.Core.Models.PublishedContent;
+using Umbraco.Cms.Web.Common.Controllers;
using Umbraco.Extensions;
using static Umbraco.Cms.Core.Constants.Web.Routing;
@@ -27,47 +28,19 @@ namespace Umbraco.Cms.Web.Common.Macros
public class PartialViewMacroEngine
{
private readonly IHttpContextAccessor _httpContextAccessor;
- private readonly IHostingEnvironment _hostingEnvironment;
- //private readonly Func _getUmbracoContext;
+ private readonly IModelMetadataProvider _modelMetadataProvider;
+ private readonly ITempDataProvider _tempDataProvider;
public PartialViewMacroEngine(
- //IUmbracoContextAccessor umbracoContextAccessor,
IHttpContextAccessor httpContextAccessor,
- IHostingEnvironment hostingEnvironment)
+ IModelMetadataProvider modelMetadataProvider,
+ ITempDataProvider tempDataProvider)
{
_httpContextAccessor = httpContextAccessor;
- _hostingEnvironment = hostingEnvironment;
-
- //_getUmbracoContext = () =>
- //{
- // var context = umbracoContextAccessor.UmbracoContext;
- // if (context == null)
- // {
- // throw new InvalidOperationException(
- // $"The {GetType()} cannot execute with a null UmbracoContext.Current reference.");
- // }
-
- // return context;
- //};
+ _modelMetadataProvider = modelMetadataProvider;
+ _tempDataProvider = tempDataProvider;
}
- //public bool Validate(string code, string tempFileName, IPublishedContent currentPage, out string errorMessage)
- //{
- // var temp = GetVirtualPathFromPhysicalPath(tempFileName);
- // try
- // {
- // CompileAndInstantiate(temp);
- // }
- // catch (Exception exception)
- // {
- // errorMessage = exception.Message;
- // return false;
- // }
-
- // errorMessage = string.Empty;
- // return true;
- //}
-
public MacroContent Execute(MacroModel macro, IPublishedContent content)
{
if (macro == null)
@@ -85,32 +58,24 @@ namespace Umbraco.Cms.Web.Common.Macros
throw new ArgumentException("The MacroSource property of the macro object cannot be null or empty");
}
- var httpContext = _httpContextAccessor.GetRequiredHttpContext();
- //var umbCtx = _getUmbracoContext();
- var routeVals = new RouteData();
- routeVals.Values.Add(ControllerToken, "PartialViewMacro");
- routeVals.Values.Add(ActionToken, "Index");
+ HttpContext httpContext = _httpContextAccessor.GetRequiredHttpContext();
+
+ RouteData currentRouteData = httpContext.GetRouteData();
- //TODO: Was required for UmbracoViewPage need to figure out if we still need that, i really don't think this is necessary
- //routeVals.DataTokens.Add(Core.Constants.Web.UmbracoContextDataToken, umbCtx);
-
- var modelMetadataProvider = httpContext.RequestServices.GetRequiredService();
- var tempDataProvider = httpContext.RequestServices.GetRequiredService();
+ // Check if there's proxied ViewData (i.e. returned from a SurfaceController)
+ ProxyViewDataFeature proxyViewDataFeature = httpContext.Features.Get();
+ ViewDataDictionary viewData = proxyViewDataFeature?.ViewData ?? new ViewDataDictionary(_modelMetadataProvider, new ModelStateDictionary());
+ ITempDataDictionary tempData = proxyViewDataFeature?.TempData ?? new TempDataDictionary(httpContext, _tempDataProvider);
var viewContext = new ViewContext(
- new ActionContext(httpContext, httpContext.GetRouteData(), new ControllerActionDescriptor()),
+ new ActionContext(httpContext, currentRouteData, new ControllerActionDescriptor()),
new FakeView(),
- new ViewDataDictionary(modelMetadataProvider, new ModelStateDictionary()),
- new TempDataDictionary(httpContext, tempDataProvider),
+ viewData,
+ tempData,
TextWriter.Null,
new HtmlHelperOptions()
);
-
- routeVals.DataTokens.Add("ParentActionViewContext", viewContext);
-
- var viewComponent = new PartialViewMacroViewComponent(macro, content);
-
var writer = new StringWriter();
var viewComponentContext = new ViewComponentContext(
new ViewComponentDescriptor(),
@@ -119,7 +84,9 @@ namespace Umbraco.Cms.Web.Common.Macros
viewContext,
writer);
- viewComponent.InvokeAsync().GetAwaiter().GetResult().Execute(viewComponentContext);
+ var viewComponent = new PartialViewMacroViewComponent(macro, content, viewComponentContext);
+
+ viewComponent.Invoke().Execute(viewComponentContext);
var output = writer.GetStringBuilder().ToString();
@@ -129,38 +96,11 @@ namespace Umbraco.Cms.Web.Common.Macros
private class FakeView : IView
{
///
- public Task RenderAsync(ViewContext context)
- {
- return Task.CompletedTask;
- }
+ public Task RenderAsync(ViewContext context) => Task.CompletedTask;
///
public string Path { get; } = "View";
}
-
- //private string GetVirtualPathFromPhysicalPath(string physicalPath)
- //{
- // var rootpath = _hostingEnvironment.MapPathContentRoot("~/");
- // physicalPath = physicalPath.Replace(rootpath, "");
- // physicalPath = physicalPath.Replace("\\", "/");
- // return "~/" + physicalPath;
- //}
-
- //private static PartialViewMacroPage CompileAndInstantiate(string virtualPath)
- //{
- // // //Compile Razor - We Will Leave This To ASP.NET Compilation Engine & ASP.NET WebPages
- // // //Security in medium trust is strict around here, so we can only pass a virtual file path
- // // //ASP.NET Compilation Engine caches returned types
- // // //Changed From BuildManager As Other Properties Are Attached Like Context Path/
- // // var webPageBase = WebPageBase.CreateInstanceFromVirtualPath(virtualPath);
- // // var webPage = webPageBase as PartialViewMacroPage;
- // // if (webPage == null)
- // // throw new InvalidCastException("All Partial View Macro views must inherit from " + typeof(PartialViewMacroPage).FullName);
- // // return webPage;
-
- // //TODO? How to check this
- // return null;
- //}
}
}
diff --git a/src/Umbraco.Web.Common/Macros/PartialViewMacroViewComponent.cs b/src/Umbraco.Web.Common/Macros/PartialViewMacroViewComponent.cs
index 2b317585b4..5cab93c00f 100644
--- a/src/Umbraco.Web.Common/Macros/PartialViewMacroViewComponent.cs
+++ b/src/Umbraco.Web.Common/Macros/PartialViewMacroViewComponent.cs
@@ -1,6 +1,7 @@
-using System.Linq;
+using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.ViewComponents;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.Macros;
using Umbraco.Cms.Core.Models;
@@ -20,13 +21,17 @@ namespace Umbraco.Cms.Web.Common.Macros
public PartialViewMacroViewComponent(
MacroModel macro,
- IPublishedContent content)
+ IPublishedContent content,
+ ViewComponentContext viewComponentContext)
{
_macro = macro;
_content = content;
+ // This must be set before Invoke is called else the call to View will end up
+ // using an empty ViewData instance because this hasn't been set yet.
+ ViewComponentContext = viewComponentContext;
}
- public async Task InvokeAsync()
+ public IViewComponentResult Invoke()
{
var model = new PartialViewMacroModel(
_content,
@@ -34,7 +39,8 @@ namespace Umbraco.Cms.Web.Common.Macros
_macro.Alias,
_macro.Name,
_macro.Properties.ToDictionary(x => x.Key, x => (object)x.Value));
- var result = View(_macro.MacroSource, model);
+
+ ViewViewComponentResult result = View(_macro.MacroSource, model);
return result;
}
diff --git a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs
index 6fdd41a757..467ec29451 100644
--- a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs
+++ b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs
@@ -10,6 +10,7 @@ using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.Logging;
+using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Infrastructure.PublishedCache;
using Umbraco.Cms.Web.Common.Profiler;
@@ -83,27 +84,26 @@ namespace Umbraco.Cms.Web.Common.Middleware
EnsureContentCacheInitialized();
- _backofficeSecurityFactory.EnsureBackOfficeSecurity(); // Needs to be before UmbracoContext, TODO: Why?
+ // TODO: This dependency chain is broken and needs to be fixed.
+ // This is required to be called before EnsureUmbracoContext else the UmbracoContext's IBackOfficeSecurity instance is null
+ // This is ugly Temporal Coupling which also means that developers can no longer just use IUmbracoContextFactory the
+ // way it was intended.
+ _backofficeSecurityFactory.EnsureBackOfficeSecurity();
UmbracoContextReference umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext();
Uri currentApplicationUrl = GetApplicationUrlFromCurrentRequest(context.Request);
_hostingEnvironment.EnsureApplicationMainUrl(currentApplicationUrl);
-
- bool isFrontEndRequest = umbracoContextReference.UmbracoContext.IsFrontEndUmbracoRequest();
-
var pathAndQuery = context.Request.GetEncodedPathAndQuery();
try
{
- if (isFrontEndRequest)
- {
- LogHttpRequest.TryGetCurrentHttpRequestId(out Guid httpRequestId, _requestCache);
- _logger.LogTrace("Begin request [{HttpRequestId}]: {RequestUrl}", httpRequestId, pathAndQuery);
- }
+ // Verbose log start of every request
+ LogHttpRequest.TryGetCurrentHttpRequestId(out Guid httpRequestId, _requestCache);
+ _logger.LogTrace("Begin request [{HttpRequestId}]: {RequestUrl}", httpRequestId, pathAndQuery);
try
- {
+ {
await _eventAggregator.PublishAsync(new UmbracoRequestBegin(umbracoContextReference.UmbracoContext));
}
catch (Exception ex)
@@ -126,11 +126,10 @@ namespace Umbraco.Cms.Web.Common.Middleware
}
finally
{
- if (isFrontEndRequest)
- {
- LogHttpRequest.TryGetCurrentHttpRequestId(out Guid httpRequestId, _requestCache);
- _logger.LogTrace("End Request [{HttpRequestId}]: {RequestUrl} ({RequestDuration}ms)", httpRequestId, pathAndQuery, DateTime.Now.Subtract(umbracoContextReference.UmbracoContext.ObjectCreated).TotalMilliseconds);
- }
+ // Verbose log end of every request (in v8 we didn't log the end request of ALL requests, only the front-end which was
+ // strange since we always logged the beginning, so now we just log start/end of all requests)
+ LogHttpRequest.TryGetCurrentHttpRequestId(out Guid httpRequestId, _requestCache);
+ _logger.LogTrace("End Request [{HttpRequestId}]: {RequestUrl} ({RequestDuration}ms)", httpRequestId, pathAndQuery, DateTime.Now.Subtract(umbracoContextReference.UmbracoContext.ObjectCreated).TotalMilliseconds);
try
{
diff --git a/src/Umbraco.Web.Common/Security/BackofficeSecurityFactory.cs b/src/Umbraco.Web.Common/Security/BackofficeSecurityFactory.cs
index 41e7f6d816..ad0731f790 100644
--- a/src/Umbraco.Web.Common/Security/BackofficeSecurityFactory.cs
+++ b/src/Umbraco.Web.Common/Security/BackofficeSecurityFactory.cs
@@ -1,11 +1,10 @@
using Microsoft.AspNetCore.Http;
-using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Web.Common.Security
{
- // TODO: This is only for the back office, does it need to be in common?
+ // TODO: This is only for the back office, does it need to be in common? YES currently UmbracoContext has an transitive dependency on this which needs to be fixed/reviewed.
public class BackOfficeSecurityFactory: IBackOfficeSecurityFactory
{
@@ -14,11 +13,11 @@ namespace Umbraco.Cms.Web.Common.Security
private readonly IHttpContextAccessor _httpContextAccessor;
public BackOfficeSecurityFactory(
- IBackOfficeSecurityAccessor backofficeSecurityAccessor,
+ IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
IUserService userService,
IHttpContextAccessor httpContextAccessor)
{
- _backOfficeSecurityAccessor = backofficeSecurityAccessor;
+ _backOfficeSecurityAccessor = backOfficeSecurityAccessor;
_userService = userService;
_httpContextAccessor = httpContextAccessor;
}
diff --git a/src/Umbraco.Web.Website/Security/UmbracoWebsiteSecurity.cs b/src/Umbraco.Web.Common/Security/UmbracoWebsiteSecurity.cs
similarity index 97%
rename from src/Umbraco.Web.Website/Security/UmbracoWebsiteSecurity.cs
rename to src/Umbraco.Web.Common/Security/UmbracoWebsiteSecurity.cs
index c878730d90..5a67f6f484 100644
--- a/src/Umbraco.Web.Website/Security/UmbracoWebsiteSecurity.cs
+++ b/src/Umbraco.Web.Common/Security/UmbracoWebsiteSecurity.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -11,9 +11,8 @@ using Umbraco.Cms.Core.Models.Security;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
-using Constants = Umbraco.Cms.Core.Constants;
-namespace Umbraco.Cms.Web.Website.Security
+namespace Umbraco.Cms.Web.Common.Security
{
public class UmbracoWebsiteSecurity : IUmbracoWebsiteSecurity
{
@@ -36,7 +35,7 @@ namespace Umbraco.Cms.Web.Website.Security
///
public RegisterModel CreateRegistrationModel(string memberTypeAlias = null)
{
- var providedOrDefaultMemberTypeAlias = memberTypeAlias ?? Constants.Conventions.MemberTypes.DefaultAlias;
+ var providedOrDefaultMemberTypeAlias = memberTypeAlias ?? Core.Constants.Conventions.MemberTypes.DefaultAlias;
var memberType = _memberTypeService.Get(providedOrDefaultMemberTypeAlias);
if (memberType == null)
{
@@ -114,7 +113,7 @@ namespace Umbraco.Cms.Web.Website.Security
public Task RegisterMemberAsync(RegisterModel model, bool logMemberIn = true)
{
- throw new System.NotImplementedException();
+ throw new NotImplementedException();
}
///
diff --git a/src/Umbraco.Web.Common/Security/UmbracoWebsiteSecurityFactory.cs b/src/Umbraco.Web.Common/Security/UmbracoWebsiteSecurityFactory.cs
new file mode 100644
index 0000000000..ec256a86cb
--- /dev/null
+++ b/src/Umbraco.Web.Common/Security/UmbracoWebsiteSecurityFactory.cs
@@ -0,0 +1,46 @@
+using Microsoft.AspNetCore.Http;
+using Umbraco.Cms.Core.Events;
+using Umbraco.Cms.Core.Security;
+using Umbraco.Cms.Core.Services;
+using Umbraco.Cms.Core.Strings;
+
+namespace Umbraco.Cms.Web.Common.Security
+{
+ ///
+ /// Ensures that the is populated on a front-end request
+ ///
+ internal sealed class UmbracoWebsiteSecurityFactory : INotificationHandler
+ {
+ private readonly IUmbracoWebsiteSecurityAccessor _umbracoWebsiteSecurityAccessor;
+ private readonly IHttpContextAccessor _httpContextAccessor;
+ private readonly IMemberService _memberService;
+ private readonly IMemberTypeService _memberTypeService;
+ private readonly IShortStringHelper _shortStringHelper;
+
+ public UmbracoWebsiteSecurityFactory(
+ IUmbracoWebsiteSecurityAccessor umbracoWebsiteSecurityAccessor,
+ IHttpContextAccessor httpContextAccessor,
+ IMemberService memberService,
+ IMemberTypeService memberTypeService,
+ IShortStringHelper shortStringHelper)
+ {
+ _umbracoWebsiteSecurityAccessor = umbracoWebsiteSecurityAccessor;
+ _httpContextAccessor = httpContextAccessor;
+ _memberService = memberService;
+ _memberTypeService = memberTypeService;
+ _shortStringHelper = shortStringHelper;
+ }
+
+ public void Handle(UmbracoRoutedRequest notification)
+ {
+ if (_umbracoWebsiteSecurityAccessor.WebsiteSecurity is null)
+ {
+ _umbracoWebsiteSecurityAccessor.WebsiteSecurity = new UmbracoWebsiteSecurity(
+ _httpContextAccessor,
+ _memberService,
+ _memberTypeService,
+ _shortStringHelper);
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Web.Common/Templates/TemplateRenderer.cs b/src/Umbraco.Web.Common/Templates/TemplateRenderer.cs
index 5818609aeb..81f034918a 100644
--- a/src/Umbraco.Web.Common/Templates/TemplateRenderer.cs
+++ b/src/Umbraco.Web.Common/Templates/TemplateRenderer.cs
@@ -36,9 +36,10 @@ namespace Umbraco.Cms.Web.Common.Templates
private readonly IFileService _fileService;
private readonly ILocalizationService _languageService;
private readonly WebRoutingSettings _webRoutingSettings;
- private readonly IShortStringHelper _shortStringHelper;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ICompositeViewEngine _viewEngine;
+ private readonly IModelMetadataProvider _modelMetadataProvider;
+ private readonly ITempDataProvider _tempDataProvider;
public TemplateRenderer(
IUmbracoContextAccessor umbracoContextAccessor,
@@ -46,18 +47,20 @@ namespace Umbraco.Cms.Web.Common.Templates
IFileService fileService,
ILocalizationService textService,
IOptions webRoutingSettings,
- IShortStringHelper shortStringHelper,
IHttpContextAccessor httpContextAccessor,
- ICompositeViewEngine viewEngine)
+ ICompositeViewEngine viewEngine,
+ IModelMetadataProvider modelMetadataProvider,
+ ITempDataProvider tempDataProvider)
{
_umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor));
_publishedRouter = publishedRouter ?? throw new ArgumentNullException(nameof(publishedRouter));
_fileService = fileService ?? throw new ArgumentNullException(nameof(fileService));
_languageService = textService ?? throw new ArgumentNullException(nameof(textService));
_webRoutingSettings = webRoutingSettings.Value ?? throw new ArgumentNullException(nameof(webRoutingSettings));
- _shortStringHelper = shortStringHelper ?? throw new ArgumentNullException(nameof(shortStringHelper));
_httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
_viewEngine = viewEngine ?? throw new ArgumentNullException(nameof(viewEngine));
+ _modelMetadataProvider = modelMetadataProvider;
+ _tempDataProvider = tempDataProvider;
}
public async Task RenderAsync(int pageId, int? altTemplateId, StringWriter writer)
@@ -156,10 +159,7 @@ namespace Umbraco.Cms.Web.Common.Templates
throw new InvalidOperationException($"A view with the name {request.GetTemplateAlias()} could not be found");
}
- var modelMetadataProvider = httpContext.RequestServices.GetRequiredService();
- var tempDataProvider = httpContext.RequestServices.GetRequiredService();
-
- var viewData = new ViewDataDictionary(modelMetadataProvider, new ModelStateDictionary())
+ var viewData = new ViewDataDictionary(_modelMetadataProvider, new ModelStateDictionary())
{
Model = request.PublishedContent
};
@@ -169,7 +169,7 @@ namespace Umbraco.Cms.Web.Common.Templates
new ActionContext(httpContext, httpContext.GetRouteData(), new ControllerActionDescriptor()),
viewResult.View,
viewData,
- new TempDataDictionary(httpContext, tempDataProvider),
+ new TempDataDictionary(httpContext, _tempDataProvider),
writer,
new HtmlHelperOptions()
);
@@ -182,6 +182,9 @@ namespace Umbraco.Cms.Web.Common.Templates
sw.Write(output);
}
+ // TODO: I feel like we need to do more than this, pretty sure we need to replace the UmbracoRouteValues
+ // HttpRequest feature too while this renders.
+
private void SetNewItemsOnContextObjects(IPublishedRequest request)
{
// now, set the new ones for this page execution
diff --git a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj
index fe8572c1ca..b4c9912f16 100644
--- a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj
+++ b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj
@@ -3,7 +3,6 @@
net5.0
Library
- latest
Umbraco.Cms.Web.Common
Umbraco.Cms.Web.Common
Umbraco CMS Web
diff --git a/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj b/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj
index 4f6bb1240f..066a27ccee 100644
--- a/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj
+++ b/src/Umbraco.Web.UI.NetCore/Umbraco.Web.UI.NetCore.csproj
@@ -3,7 +3,6 @@
net5.0
Umbraco.Cms.Web.UI.NetCore
- latest
Umbraco.Cms.Web.UI.NetCore
diff --git a/src/Umbraco.Web.Website/Controllers/SurfaceController.cs b/src/Umbraco.Web.Website/Controllers/SurfaceController.cs
index a0798d2fd0..b86af23999 100644
--- a/src/Umbraco.Web.Website/Controllers/SurfaceController.cs
+++ b/src/Umbraco.Web.Website/Controllers/SurfaceController.cs
@@ -98,7 +98,7 @@ namespace Umbraco.Cms.Web.Website.Controllers
///
protected UmbracoPageResult CurrentUmbracoPage()
{
- HttpContext.Features.Set(new ProxyViewDataFeature(ViewData));
+ HttpContext.Features.Set(new ProxyViewDataFeature(ViewData, TempData));
return new UmbracoPageResult(ProfilingLogger);
}
}
diff --git a/src/Umbraco.Web.Website/Controllers/UmbLoginController.cs b/src/Umbraco.Web.Website/Controllers/UmbLoginController.cs
index 67c4cd9bf7..93b1f23b76 100644
--- a/src/Umbraco.Web.Website/Controllers/UmbLoginController.cs
+++ b/src/Umbraco.Web.Website/Controllers/UmbLoginController.cs
@@ -1,4 +1,5 @@
-using System.Threading.Tasks;
+using System;
+using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Logging;
@@ -17,8 +18,13 @@ namespace Umbraco.Cms.Web.Website.Controllers
{
private readonly IUmbracoWebsiteSecurityAccessor _websiteSecurityAccessor;
- public UmbLoginController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory,
- ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IPublishedUrlProvider publishedUrlProvider,
+ public UmbLoginController(
+ IUmbracoContextAccessor umbracoContextAccessor,
+ IUmbracoDatabaseFactory databaseFactory,
+ ServiceContext services,
+ AppCaches appCaches,
+ IProfilingLogger profilingLogger,
+ IPublishedUrlProvider publishedUrlProvider,
IUmbracoWebsiteSecurityAccessor websiteSecurityAccessor)
: base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider)
{
diff --git a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs
index 3823cde255..58074ac9a5 100644
--- a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs
+++ b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs
@@ -2,8 +2,10 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.DependencyInjection;
+using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Infrastructure.DependencyInjection;
using Umbraco.Cms.Web.Common.Routing;
+using Umbraco.Cms.Web.Common.Security;
using Umbraco.Cms.Web.Website.Collections;
using Umbraco.Cms.Web.Website.Controllers;
using Umbraco.Cms.Web.Website.Routing;
@@ -40,7 +42,7 @@ namespace Umbraco.Extensions
builder.Services.AddSingleton();
builder.Services.AddSingleton();
- builder.Services.AddSingleton();
+ builder.Services.AddSingleton();
builder
.AddDistributedCache()
diff --git a/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs b/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs
index 1502a51665..ddca7f37aa 100644
--- a/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs
+++ b/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs
@@ -165,16 +165,11 @@ namespace Umbraco.Extensions
return htmlHelper.ValidationSummary(excludePropertyErrors, message, htmlAttributes);
}
- var htmlGenerator = GetRequiredService(htmlHelper);
+ IHtmlGenerator htmlGenerator = GetRequiredService(htmlHelper);
- var viewContext = htmlHelper.ViewContext.Clone();
- foreach (var key in viewContext.ViewData.Keys.ToArray())
- {
- if (!key.StartsWith(prefix))
- {
- viewContext.ViewData.Remove(key);
- }
- }
+ ViewContext viewContext = htmlHelper.ViewContext.Clone();
+ //change the HTML field name
+ viewContext.ViewData.TemplateInfo.HtmlFieldPrefix = prefix;
var tagBuilder = htmlGenerator.GenerateValidationSummary(
viewContext,
diff --git a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs
index d0e5d4c72a..c5d13b721a 100644
--- a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs
+++ b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs
@@ -13,6 +13,7 @@ using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
+using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
@@ -48,6 +49,7 @@ namespace Umbraco.Cms.Web.Website.Routing
private readonly IRoutableDocumentFilter _routableDocumentFilter;
private readonly IDataProtectionProvider _dataProtectionProvider;
private readonly IControllerActionSearcher _controllerActionSearcher;
+ private readonly IEventAggregator _eventAggregator;
///
/// Initializes a new instance of the class.
@@ -62,7 +64,8 @@ namespace Umbraco.Cms.Web.Website.Routing
IUmbracoRouteValuesFactory routeValuesFactory,
IRoutableDocumentFilter routableDocumentFilter,
IDataProtectionProvider dataProtectionProvider,
- IControllerActionSearcher controllerActionSearcher)
+ IControllerActionSearcher controllerActionSearcher,
+ IEventAggregator eventAggregator)
{
if (globalSettings is null)
{
@@ -79,6 +82,7 @@ namespace Umbraco.Cms.Web.Website.Routing
_routableDocumentFilter = routableDocumentFilter ?? throw new ArgumentNullException(nameof(routableDocumentFilter));
_dataProtectionProvider = dataProtectionProvider;
_controllerActionSearcher = controllerActionSearcher;
+ _eventAggregator = eventAggregator;
}
///
@@ -117,6 +121,9 @@ namespace Umbraco.Cms.Web.Website.Routing
// Store the route values as a httpcontext feature
httpContext.Features.Set(umbracoRouteValues);
+ // publish an event that we've routed a request
+ await _eventAggregator.PublishAsync(new UmbracoRoutedRequest(_umbracoContextAccessor.UmbracoContext));
+
// Need to check if there is form data being posted back to an Umbraco URL
PostedDataProxyInfo postedInfo = GetFormInfo(httpContext, values);
if (postedInfo != null)
diff --git a/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj b/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj
index 6815016713..a7c5e7a277 100644
--- a/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj
+++ b/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj
@@ -3,7 +3,6 @@
net5.0
Library
- latest
Umbraco.Cms.Web.Website
Umbraco.Cms.Web.Website
Umbraco CMS Website