diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Extensions/HtmlHelperExtensionMethodsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Extensions/HtmlHelperExtensionMethodsTests.cs
new file mode 100644
index 0000000000..abb44a5dfb
--- /dev/null
+++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Extensions/HtmlHelperExtensionMethodsTests.cs
@@ -0,0 +1,118 @@
+using System.Text.Encodings.Web;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+using Microsoft.AspNetCore.Mvc.ViewEngines;
+using Microsoft.AspNetCore.Mvc.ViewFeatures;
+using Microsoft.AspNetCore.Mvc.ViewFeatures.Buffers;
+using Microsoft.Extensions.WebEncoders.Testing;
+using Moq;
+using NUnit.Framework;
+using Umbraco.Extensions;
+
+namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Filters
+{
+
+ [TestFixture]
+ public class HtmlHelperExtensionMethodsTests
+ {
+ private const string SampleWithAnchorElement = "Hello world, this is some text with a link";
+ private const string SampleWithBoldAndAnchorElements = "Hello world, this is some text with a link";
+
+ [SetUp]
+ public virtual void Initialize()
+ {
+ //create an empty htmlHelper
+ _htmlHelper = new HtmlHelper(Mock.Of(),
+ Mock.Of(),
+ Mock.Of(),
+ Mock.Of(),
+ new HtmlTestEncoder(),
+ UrlEncoder.Default);
+ }
+
+ private HtmlHelper _htmlHelper;
+
+ [Test]
+ public void Truncate_Simple()
+ {
+ var result = _htmlHelper.Truncate(SampleWithAnchorElement, 25).ToString();
+
+ Assert.AreEqual("Hello world, this is some…", result);
+ }
+
+ [Test]
+ public void When_Truncating_A_String_Ends_With_A_Space_We_Should_Trim_The_Space_Before_Appending_The_Ellipsis()
+ {
+ var result = _htmlHelper.Truncate(SampleWithAnchorElement, 26).ToString();
+
+ Assert.AreEqual("Hello world, this is some…", result);
+ }
+
+ [Test]
+ public void Truncate_Inside_Word()
+ {
+ var result = _htmlHelper.Truncate(SampleWithAnchorElement, 24).ToString();
+
+ Assert.AreEqual("Hello world, this is som…", result);
+ }
+
+ [Test]
+ public void Truncate_With_Tag()
+ {
+ var result = _htmlHelper.Truncate(SampleWithAnchorElement, 35).ToString();
+
+ Assert.AreEqual("Hello world, this is some text with…", result);
+ }
+
+ [Test]
+ public void Truncate_By_Words()
+ {
+ var result = _htmlHelper.TruncateByWords(SampleWithAnchorElement, 4).ToString();
+
+ Assert.AreEqual("Hello world, this is…", result);
+ }
+
+ [Test]
+ public void Truncate_By_Words_With_Tag()
+ {
+ var result = _htmlHelper.TruncateByWords(SampleWithBoldAndAnchorElements, 4).ToString();
+
+ Assert.AreEqual("Hello world, this is…", result);
+ }
+
+ [Test]
+ public void Truncate_By_Words_Mid_Tag()
+ {
+ var result = _htmlHelper.TruncateByWords(SampleWithAnchorElement, 7).ToString();
+
+ Assert.AreEqual("Hello world, this is some text with…", result);
+ }
+
+ [Test]
+ public void Strip_All_Html()
+ {
+ var result = _htmlHelper.StripHtml(SampleWithBoldAndAnchorElements, null).ToString();
+
+ Assert.AreEqual("Hello world, this is some text with a link", result);
+ }
+
+ [Test]
+ public void Strip_Specific_Html()
+ {
+ string[] tags = { "b" };
+
+ var result = _htmlHelper.StripHtml(SampleWithBoldAndAnchorElements, tags).ToString();
+
+ Assert.AreEqual(SampleWithAnchorElement, result);
+ }
+
+ [Test]
+ public void Strip_Invalid_Html()
+ {
+ const string text = "Hello world, is some text with a link";
+
+ var result = _htmlHelper.StripHtml(text).ToString();
+
+ Assert.AreEqual("Hello world, is some text with a link", result);
+ }
+ }
+}
diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringFilterTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringFilterTests.cs
new file mode 100644
index 0000000000..3ed4a28b06
--- /dev/null
+++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringFilterTests.cs
@@ -0,0 +1,41 @@
+using Microsoft.AspNetCore.DataProtection;
+using NUnit.Framework;
+using Umbraco.Web.Common.Exceptions;
+using Umbraco.Web.Common.Filters;
+using Umbraco.Web.Common.Security;
+
+namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Filters
+{
+ [TestFixture]
+ public class ValidateUmbracoFormRouteStringFilterTests
+ {
+ private IDataProtectionProvider DataProtectionProvider { get; } = new EphemeralDataProtectionProvider();
+
+ [Test]
+ public void Validate_Route_String()
+ {
+ var filter = new ValidateUmbracoFormRouteStringAttribute.ValidateUmbracoFormRouteStringFilter(DataProtectionProvider);
+
+ Assert.Throws(() => filter.ValidateRouteString(null, null, null, null));
+
+ const string ControllerName = "Test";
+ const string ControllerAction = "Index";
+ const string Area = "MyArea";
+ var validUfprt = EncryptionHelper.CreateEncryptedRouteString(DataProtectionProvider, ControllerName, ControllerAction, Area);
+
+ var invalidUfprt = validUfprt + "z";
+ Assert.Throws(() => filter.ValidateRouteString(invalidUfprt, null, null, null));
+
+ Assert.Throws(() => filter.ValidateRouteString(validUfprt, ControllerName, ControllerAction, "doesntMatch"));
+ Assert.Throws(() => filter.ValidateRouteString(validUfprt, ControllerName, ControllerAction, null));
+ Assert.Throws(() => filter.ValidateRouteString(validUfprt, ControllerName, "doesntMatch", Area));
+ Assert.Throws(() => filter.ValidateRouteString(validUfprt, ControllerName, null, Area));
+ Assert.Throws(() => filter.ValidateRouteString(validUfprt, "doesntMatch", ControllerAction, Area));
+ Assert.Throws(() => filter.ValidateRouteString(validUfprt, null, ControllerAction, Area));
+
+ Assert.DoesNotThrow(() => filter.ValidateRouteString(validUfprt, ControllerName, ControllerAction, Area));
+ Assert.DoesNotThrow(() => filter.ValidateRouteString(validUfprt, ControllerName.ToLowerInvariant(), ControllerAction.ToLowerInvariant(), Area.ToLowerInvariant()));
+ }
+
+ }
+}
diff --git a/src/Umbraco.Tests/Web/Mvc/HtmlStringUtilitiesTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Mvc/HtmlStringUtilitiesTests.cs
similarity index 94%
rename from src/Umbraco.Tests/Web/Mvc/HtmlStringUtilitiesTests.cs
rename to src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Mvc/HtmlStringUtilitiesTests.cs
index 36ddecc676..4b1675b7f0 100644
--- a/src/Umbraco.Tests/Web/Mvc/HtmlStringUtilitiesTests.cs
+++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Mvc/HtmlStringUtilitiesTests.cs
@@ -1,7 +1,8 @@
using NUnit.Framework;
using Umbraco.Web;
+using Umbraco.Web.Common.Mvc;
-namespace Umbraco.Tests.Web.Mvc
+namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Mvc
{
[TestFixture]
public class HtmlStringUtilitiesTests
diff --git a/src/Umbraco.Tests/Web/UrlHelperExtensionTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Security/EncryptionHelperTests.cs
similarity index 59%
rename from src/Umbraco.Tests/Web/UrlHelperExtensionTests.cs
rename to src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Security/EncryptionHelperTests.cs
index a4b96ab4ff..db80e2cd74 100644
--- a/src/Umbraco.Tests/Web/UrlHelperExtensionTests.cs
+++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Security/EncryptionHelperTests.cs
@@ -1,15 +1,20 @@
using System.Collections.Generic;
+using Microsoft.AspNetCore.DataProtection;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Web;
+using Umbraco.Web.Common.Security;
-namespace Umbraco.Tests.Web
+namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Security
{
[TestFixture]
- public class UrlHelperExtensionTests
+ public class EncryptionHelperTests
{
+
+ private IDataProtectionProvider DataProtectionProvider { get; } = new EphemeralDataProtectionProvider();
+
[Test]
- public static void Create_Encrypted_RouteString_From_Anonymous_Object()
+ public void Create_Encrypted_RouteString_From_Anonymous_Object()
{
var additionalRouteValues = new
{
@@ -19,14 +24,15 @@ namespace Umbraco.Tests.Web
keY4 = "valuE4"
};
- var encryptedRouteString = UrlHelperRenderExtensions.CreateEncryptedRouteString(
+ var encryptedRouteString = EncryptionHelper.CreateEncryptedRouteString(
+ DataProtectionProvider,
"FormController",
"FormAction",
"",
additionalRouteValues
);
- var result = encryptedRouteString.DecryptWithMachineKey();
+ var result = EncryptionHelper.Decrypt(encryptedRouteString, DataProtectionProvider);
const string expectedResult = "c=FormController&a=FormAction&ar=&key1=value1&key2=value2&Key3=Value3&keY4=valuE4";
@@ -34,7 +40,7 @@ namespace Umbraco.Tests.Web
}
[Test]
- public static void Create_Encrypted_RouteString_From_Dictionary()
+ public void Create_Encrypted_RouteString_From_Dictionary()
{
var additionalRouteValues = new Dictionary()
{
@@ -44,14 +50,15 @@ namespace Umbraco.Tests.Web
{"keY4", "valuE4"}
};
- var encryptedRouteString = UrlHelperRenderExtensions.CreateEncryptedRouteString(
+ var encryptedRouteString = EncryptionHelper.CreateEncryptedRouteString(
+ DataProtectionProvider,
"FormController",
"FormAction",
"",
additionalRouteValues
);
- var result = encryptedRouteString.DecryptWithMachineKey();
+ var result = EncryptionHelper.Decrypt(encryptedRouteString, DataProtectionProvider);
const string expectedResult = "c=FormController&a=FormAction&ar=&key1=value1&key2=value2&Key3=Value3&keY4=valuE4";
diff --git a/src/Umbraco.Tests/Publishing/PublishingStrategyTests.cs b/src/Umbraco.Tests/Publishing/PublishingStrategyTests.cs
deleted file mode 100644
index 342aa99b47..0000000000
--- a/src/Umbraco.Tests/Publishing/PublishingStrategyTests.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-using System.Collections.Generic;
-using NUnit.Framework;
-using Umbraco.Core;
-using Umbraco.Core.Events;
-using Umbraco.Core.Models;
-using Umbraco.Tests.TestHelpers;
-using Umbraco.Tests.TestHelpers.Entities;
-using System.Linq;
-using Microsoft.Extensions.DependencyInjection;
-using Umbraco.Core.Services;
-using Umbraco.Tests.Testing;
-
-namespace Umbraco.Tests.Publishing
-{
- [TestFixture]
- [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
- public class PublishingStrategyTests : TestWithDatabaseBase
- {
- private IContent _homePage;
-
- [NUnit.Framework.Ignore("fixme - ignored test")]
- [Test]
- public void Can_Publish_And_Update_Xml_Cache()
- {
- // TODO: Create new test
- }
-
- public IEnumerable CreateTestData()
- {
- //NOTE Maybe not the best way to create/save test data as we are using the services, which are being tested.
-
- //Create and Save ContentType "umbTextpage" -> 1045
- ContentType contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage", "Textpage");
- ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType!
- ServiceContext.ContentTypeService.Save(contentType);
- var mandatoryType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true);
- //ServiceContext.FileService.SaveTemplate(mandatoryType.DefaultTemplate); // else, FK violation on contentType!
- ServiceContext.ContentTypeService.Save(mandatoryType);
-
- //Create and Save Content "Homepage" based on "umbTextpage" -> 1046
- _homePage = MockedContent.CreateSimpleContent(contentType);
- ServiceContext.ContentService.Save(_homePage, 0);
-
- //Create and Save Content "Text Page 1" based on "umbTextpage" -> 1047
- Content subpage = MockedContent.CreateSimpleContent(contentType, "Text Page 1", _homePage.Id);
- ServiceContext.ContentService.Save(subpage, 0);
-
- //Create and Save Content "Text Page 2" based on "umbTextpage" -> 1048
- Content subpage2 = MockedContent.CreateSimpleContent(contentType, "Text Page 2", _homePage.Id);
- ServiceContext.ContentService.Save(subpage2, 0);
-
- //Create and Save Content "Text Page 3" based on "umbTextpage" -> 1048
- Content subpage3 = MockedContent.CreateSimpleContent(contentType, "Text Page 3", subpage2.Id);
- ServiceContext.ContentService.Save(subpage3, 0);
-
- return new[] {_homePage, subpage, subpage2, subpage3};
- }
- }
-}
diff --git a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs
index de20211774..b3663738dd 100644
--- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs
+++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs
@@ -48,7 +48,7 @@ namespace Umbraco.Tests.Routing
new TestUmbracoContextAccessor(),
TestObjects.GetGlobalSettings(),
ShortStringHelper,
- new SurfaceControllerTypeCollection(Enumerable.Empty()),
+ // new SurfaceControllerTypeCollection(Enumerable.Empty()),
new UmbracoApiControllerTypeCollection(Enumerable.Empty()),
HostingEnvironment);
}
@@ -69,8 +69,8 @@ namespace Umbraco.Tests.Routing
// set the default RenderMvcController
Current.DefaultRenderMvcControllerType = typeof(RenderMvcController); // FIXME: Wrong!
- var surfaceControllerTypes = new SurfaceControllerTypeCollection(Composition.TypeLoader.GetSurfaceControllers());
- Composition.Services.AddUnique(surfaceControllerTypes);
+ // var surfaceControllerTypes = new SurfaceControllerTypeCollection(Composition.TypeLoader.GetSurfaceControllers());
+ // Composition.Services.AddUnique(surfaceControllerTypes);
var umbracoApiControllerTypes = new UmbracoApiControllerTypeCollection(Composition.TypeLoader.GetUmbracoApiControllers());
Composition.Services.AddUnique(umbracoApiControllerTypes);
diff --git a/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs b/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs
deleted file mode 100644
index 70beb3643a..0000000000
--- a/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs
+++ /dev/null
@@ -1,173 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Examine;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Options;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Logging.Abstractions;
-using Moq;
-using NUnit.Framework;
-using Umbraco.Core;
-using Umbraco.Core.Cache;
-using Umbraco.Core.Composing;
-using Umbraco.Core.Configuration;
-using Umbraco.Core.Configuration.Models;
-using Umbraco.Core.Exceptions;
-using Umbraco.Core.Hosting;
-using Umbraco.Core.IO;
-using Umbraco.Core.Logging;
-using Umbraco.Core.Persistence;
-using Umbraco.Core.Runtime;
-using Umbraco.Net;
-using Umbraco.Tests.TestHelpers;
-using Umbraco.Tests.TestHelpers.Stubs;
-using Umbraco.Web;
-using Umbraco.Web.Hosting;
-using Umbraco.Web.Runtime;
-using ConnectionStrings = Umbraco.Core.Configuration.Models.ConnectionStrings;
-using Current = Umbraco.Web.Composing.Current;
-
-namespace Umbraco.Tests.Runtimes
-{
- [TestFixture]
- public class CoreRuntimeTests
- {
- [SetUp]
- public void SetUp()
- {
- TestComponent.Reset();
- }
-
- public void TearDown()
- {
- TestComponent.Reset();
- }
-
-
- // test application
- public class TestUmbracoApplication : UmbracoApplicationBase
- {
- public TestUmbracoApplication() : base(new NullLogger(),
- NullLoggerFactory.Instance,
- new SecuritySettings(),
- new GlobalSettings(),
- new ConnectionStrings(),
- _ioHelper, _profiler, new AspNetHostingEnvironment(Options.Create(new HostingSettings())), new AspNetBackOfficeInfo(_globalSettings, _ioHelper, new NullLogger(), Options.Create(new WebRoutingSettings())))
- {
- }
-
- private static readonly IIOHelper _ioHelper = TestHelper.IOHelper;
- private static readonly IProfiler _profiler = new TestProfiler();
- private static readonly GlobalSettings _globalSettings = new GlobalSettings();
-
-
-
- protected override CoreRuntimeBootstrapper GetRuntime(GlobalSettings globalSettings, ConnectionStrings connectionStrings, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, ILoggerFactory loggerFactory, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo)
- {
- return new TestRuntimeBootstrapper(globalSettings, connectionStrings, umbracoVersion, ioHelper, logger, loggerFactory, profiler, hostingEnvironment, backOfficeInfo);
- }
- }
-
- // test runtime
- public class TestRuntimeBootstrapper : CoreRuntimeBootstrapper
- {
- public TestRuntimeBootstrapper(GlobalSettings globalSettings, ConnectionStrings connectionStrings, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, ILoggerFactory loggerFactory, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo)
- :base(globalSettings, connectionStrings,umbracoVersion, ioHelper, loggerFactory, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, TestHelper.GetTypeFinder(), AppCaches.NoCache)
- {
-
- }
-
- // must override the database factory
- // else BootFailedException because U cannot connect to the configured db
- protected internal override IUmbracoDatabaseFactory CreateBootstrapDatabaseFactory()
- {
- var mock = new Mock();
- mock.Setup(x => x.Configured).Returns(true);
- mock.Setup(x => x.CanConnect).Returns(true);
- return mock.Object;
- }
-
- public override void Configure(IServiceCollection services)
- {
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
-
-
- base.Configure(services);
- }
-
- // runs with only one single component
- // UmbracoCoreComponent will be force-added too
- // and that's it
- protected override IEnumerable GetComposerTypes(TypeLoader typeLoader)
- {
- return new[] { typeof(TestComposer) };
- }
- }
-
-
- public class TestComposer : IComposer
- {
- // test flags
- public static bool Ctored;
- public static bool Composed;
-
- public static void Reset()
- {
- Ctored = Composed = false;
- }
-
- public TestComposer()
- {
- Ctored = true;
- }
-
- public void Compose(Composition composition)
- {
- composition.Services.AddUnique();
- composition.Components().Append();
-
- Composed = true;
- }
- }
-
- public class TestComponent : IComponent, IDisposable
- {
- // test flags
- public static bool Ctored;
- public static bool Initialized;
- public static bool Terminated;
- public static IProfilingLogger ProfilingLogger;
-
- public bool Disposed;
-
- public static void Reset()
- {
- Ctored = Initialized = Terminated = false;
- ProfilingLogger = null;
- }
-
- public TestComponent(IProfilingLogger proflog)
- {
- Ctored = true;
- ProfilingLogger = proflog;
- }
-
- public void Initialize()
- {
- Initialized = true;
- }
-
- public void Terminate()
- {
- Terminated = true;
- }
-
- public void Dispose()
- {
- Disposed = true;
- }
- }
- }
-}
diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj
index 5d6d4222e4..ec62d7f1f5 100644
--- a/src/Umbraco.Tests/Umbraco.Tests.csproj
+++ b/src/Umbraco.Tests/Umbraco.Tests.csproj
@@ -141,7 +141,6 @@
-
@@ -202,20 +201,16 @@
-
-
-
-
@@ -242,7 +237,6 @@
-
@@ -283,7 +277,6 @@
-
diff --git a/src/Umbraco.Tests/Web/Controllers/BackOfficeControllerUnitTests.cs b/src/Umbraco.Tests/Web/Controllers/BackOfficeControllerUnitTests.cs
deleted file mode 100644
index fa9335bc3f..0000000000
--- a/src/Umbraco.Tests/Web/Controllers/BackOfficeControllerUnitTests.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System.Linq;
-using NUnit.Framework;
-using Umbraco.Web.Editors;
-
-namespace Umbraco.Tests.Web.Controllers
-{
- [TestFixture]
- public class BackOfficeControllerUnitTests
- {
- public static object[] TestLegacyJsActionPaths = new object[] {
- new string[]
- {
- "alert('hello');",
- "function test() { window.location = 'http://www.google.com'; }",
- "function openCourierSecurity(userid){ UmbClientMgr.contentFrame('page?userid=123); }",
- @"function openRepository(repo, folder){ UmbClientMgr.contentFrame('page?repo=repo&folder=folder); }
- function openTransfer(revision, repo, folder){ UmbClientMgr.contentFrame('page?revision=revision&repo=repo&folder=folder); }",
- "umbraco/js/test.js",
- "/umbraco/js/test.js",
- "~/umbraco/js/test.js"
- }
- };
-
-
- }
-}
diff --git a/src/Umbraco.Tests/Web/Mvc/HtmlHelperExtensionMethodsTests.cs b/src/Umbraco.Tests/Web/Mvc/HtmlHelperExtensionMethodsTests.cs
deleted file mode 100644
index 1a4220c83b..0000000000
--- a/src/Umbraco.Tests/Web/Mvc/HtmlHelperExtensionMethodsTests.cs
+++ /dev/null
@@ -1,131 +0,0 @@
-using System.Web.Mvc;
-using NUnit.Framework;
-using Umbraco.Web;
-
-namespace Umbraco.Tests.Web.Mvc
-{
-
- [TestFixture]
- public class HtmlHelperExtensionMethodsTests
- {
- private const string SampleWithAnchorElement = "Hello world, this is some text with a link";
- private const string SampleWithBoldAndAnchorElements = "Hello world, this is some text with a link";
-
- [SetUp]
- public virtual void Initialize()
- {
- //create an empty htmlHelper
- _htmlHelper = new HtmlHelper(new ViewContext(), new ViewPage());
- }
-
- private HtmlHelper _htmlHelper;
-
- [Test]
- public void Wrap_Simple()
- {
- var output = _htmlHelper.Wrap("div", "hello world");
- Assert.AreEqual("hello world
", output.ToHtmlString());
- }
-
- [Test]
- public void Wrap_Object_Attributes()
- {
- var output = _htmlHelper.Wrap("div", "hello world", new {style = "color:red;", onclick = "void();"});
- Assert.AreEqual("hello world
", output.ToHtmlString());
- }
-
- [Test]
- public static void Truncate_Simple()
- {
- var helper = new HtmlHelper(new ViewContext(), new ViewPage());
- var result = helper.Truncate(SampleWithAnchorElement, 25).ToString();
-
- Assert.AreEqual("Hello world, this is some…", result);
- }
-
- [Test]
- public static void When_Truncating_A_String_Ends_With_A_Space_We_Should_Trim_The_Space_Before_Appending_The_Ellipsis()
- {
- var helper = new HtmlHelper(new ViewContext(), new ViewPage());
- var result = helper.Truncate(SampleWithAnchorElement, 26).ToString();
-
- Assert.AreEqual("Hello world, this is some…", result);
- }
-
- [Test]
- public static void Truncate_Inside_Word()
- {
- var helper = new HtmlHelper(new ViewContext(), new ViewPage());
- var result = helper.Truncate(SampleWithAnchorElement, 24).ToString();
-
- Assert.AreEqual("Hello world, this is som…", result);
- }
-
- [Test]
- public static void Truncate_With_Tag()
- {
- var helper = new HtmlHelper(new ViewContext(), new ViewPage());
- var result = helper.Truncate(SampleWithAnchorElement, 35).ToString();
-
- Assert.AreEqual("Hello world, this is some text with…", result);
- }
-
- [Test]
- public static void Truncate_By_Words()
- {
- var helper = new HtmlHelper(new ViewContext(), new ViewPage());
- var result = helper.TruncateByWords(SampleWithAnchorElement, 4).ToString();
-
- Assert.AreEqual("Hello world, this is…", result);
- }
-
- [Test]
- public static void Truncate_By_Words_With_Tag()
- {
- var helper = new HtmlHelper(new ViewContext(), new ViewPage());
- var result = helper.TruncateByWords(SampleWithBoldAndAnchorElements, 4).ToString();
-
- Assert.AreEqual("Hello world, this is…", result);
- }
-
- [Test]
- public static void Truncate_By_Words_Mid_Tag()
- {
- var helper = new HtmlHelper(new ViewContext(), new ViewPage());
- var result = helper.TruncateByWords(SampleWithAnchorElement, 7).ToString();
-
- Assert.AreEqual("Hello world, this is some text with…", result);
- }
-
- [Test]
- public static void Strip_All_Html()
- {
- var helper = new HtmlHelper(new ViewContext(), new ViewPage());
- var result = helper.StripHtml(SampleWithBoldAndAnchorElements, null).ToString();
-
- Assert.AreEqual("Hello world, this is some text with a link", result);
- }
-
- [Test]
- public static void Strip_Specific_Html()
- {
- string[] tags = { "b" };
-
- var helper = new HtmlHelper(new ViewContext(), new ViewPage());
- var result = helper.StripHtml(SampleWithBoldAndAnchorElements, tags).ToString();
-
- Assert.AreEqual(SampleWithAnchorElement, result);
- }
-
- [Test]
- public static void Strip_Invalid_Html()
- {
- const string text = "Hello world, is some text with a link";
-
- var helper = new HtmlHelper(new ViewContext(), new ViewPage());
- var result = helper.StripHtml(text).ToString();
-
- Assert.AreEqual("Hello world, is some text with a link", result);
- }
- }
-}
diff --git a/src/Umbraco.Tests/Web/Mvc/ValidateUmbracoFormRouteStringAttributeTests.cs b/src/Umbraco.Tests/Web/Mvc/ValidateUmbracoFormRouteStringAttributeTests.cs
deleted file mode 100644
index d4c3b7c887..0000000000
--- a/src/Umbraco.Tests/Web/Mvc/ValidateUmbracoFormRouteStringAttributeTests.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using NUnit.Framework;
-using Umbraco.Web;
-using Umbraco.Web.Mvc;
-
-namespace Umbraco.Tests.Web.Mvc
-{
- [TestFixture]
- public class ValidateUmbracoFormRouteStringAttributeTests
- {
- [Test]
- public void Validate_Route_String()
- {
- var attribute = new ValidateUmbracoFormRouteStringAttribute();
-
- Assert.Throws(() => attribute.ValidateRouteString(null, null, null, null));
-
- const string ControllerName = "Test";
- const string ControllerAction = "Index";
- const string Area = "MyArea";
- var validUfprt = UrlHelperRenderExtensions.CreateEncryptedRouteString(ControllerName, ControllerAction, Area);
-
- var invalidUfprt = validUfprt + "z";
- Assert.Throws(() => attribute.ValidateRouteString(invalidUfprt, null, null, null));
-
- Assert.Throws(() => attribute.ValidateRouteString(validUfprt, ControllerName, ControllerAction, "doesntMatch"));
- Assert.Throws(() => attribute.ValidateRouteString(validUfprt, ControllerName, ControllerAction, null));
- Assert.Throws(() => attribute.ValidateRouteString(validUfprt, ControllerName, "doesntMatch", Area));
- Assert.Throws(() => attribute.ValidateRouteString(validUfprt, ControllerName, null, Area));
- Assert.Throws(() => attribute.ValidateRouteString(validUfprt, "doesntMatch", ControllerAction, Area));
- Assert.Throws(() => attribute.ValidateRouteString(validUfprt, null, ControllerAction, Area));
-
- Assert.DoesNotThrow(() => attribute.ValidateRouteString(validUfprt, ControllerName, ControllerAction, Area));
- Assert.DoesNotThrow(() => attribute.ValidateRouteString(validUfprt, ControllerName.ToLowerInvariant(), ControllerAction.ToLowerInvariant(), Area.ToLowerInvariant()));
- }
-
- }
-}
diff --git a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs
index 511254e96b..928c0dcd3d 100644
--- a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs
@@ -95,7 +95,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// Returns the configuration for the backoffice user membership provider - used to configure the change password dialog
///
///
- [UmbracoAuthorize]
+ [UmbracoBackOfficeAuthorize]
public IDictionary GetPasswordConfig(int userId)
{
return _passwordConfiguration.GetConfiguration(userId != _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id);
@@ -183,7 +183,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// is valid before the login screen is displayed. The Auth cookie can be persisted for up to a day but the csrf cookies are only session
/// cookies which means that the auth cookie could be valid but the csrf cookies are no longer there, in that case we need to re-set the csrf cookies.
///
- [UmbracoAuthorize]
+ [UmbracoBackOfficeAuthorize]
[SetAngularAntiForgeryTokens]
//[CheckIfUserTicketDataIsStale] // TODO: Migrate this, though it will need to be done differently at the cookie auth level
public UserDetail GetCurrentUser()
@@ -205,7 +205,7 @@ namespace Umbraco.Web.BackOffice.Controllers
///
/// We cannot user GetCurrentUser since that requires they are approved, this is the same as GetCurrentUser but doesn't require them to be approved
///
- [UmbracoAuthorize(redirectToUmbracoLogin: false, requireApproval: false)]
+ [UmbracoBackOfficeAuthorize(redirectToUmbracoLogin: false, requireApproval: false)]
[SetAngularAntiForgeryTokens]
public ActionResult GetCurrentInvitedUser()
{
diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs
index 99eae2c459..06ac53441b 100644
--- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs
@@ -5,6 +5,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging;
@@ -220,7 +221,7 @@ namespace Umbraco.Web.BackOffice.Controllers
return nestedDictionary;
}
- [UmbracoAuthorize(Order = 0)]
+ [UmbracoBackOfficeAuthorize(Order = 0)]
[HttpGet]
public IEnumerable GetGridConfig()
{
@@ -231,7 +232,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// Returns the JavaScript object representing the static server variables javascript object
///
///
- [UmbracoAuthorize(Order = 0)]
+ [UmbracoBackOfficeAuthorize(Order = 0)]
[MinifyJavaScriptResult(Order = 1)]
public async Task ServerVariables()
{
diff --git a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs
index 6dd7164520..709be76acc 100644
--- a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs
@@ -131,7 +131,7 @@ namespace Umbraco.Web.BackOffice.Controllers
///
///
[HttpGet]
- [UmbracoAuthorize, OverrideAuthorization]
+ [UmbracoBackOfficeAuthorize, OverrideAuthorization]
public bool AllowsCultureVariation()
{
var contentTypes = _contentTypeService.GetAll();
diff --git a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs
index 0254021b40..3605e65563 100644
--- a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs
@@ -170,7 +170,7 @@ namespace Umbraco.Web.BackOffice.Controllers
///
/// This only works when the user is logged in (partially)
///
- [UmbracoAuthorize(redirectToUmbracoLogin: false, requireApproval : true)]
+ [UmbracoBackOfficeAuthorize(redirectToUmbracoLogin: false, requireApproval : true)]
public async Task PostSetInvitedUserPassword([FromBody]string newPassword)
{
var user = await _backOfficeUserManager.FindByIdAsync(_backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0).ToString());
@@ -235,7 +235,7 @@ namespace Umbraco.Web.BackOffice.Controllers
throw HttpResponseException.CreateValidationErrorResponse(ModelState);
}
- [UmbracoAuthorize]
+ [UmbracoBackOfficeAuthorize]
[ValidateAngularAntiForgeryToken]
public async Task> GetCurrentUserLinkedLogins()
{
diff --git a/src/Umbraco.Web.BackOffice/Controllers/DashboardController.cs b/src/Umbraco.Web.BackOffice/Controllers/DashboardController.cs
index 0d341e9a04..4d12f8db0c 100644
--- a/src/Umbraco.Web.BackOffice/Controllers/DashboardController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/DashboardController.cs
@@ -29,7 +29,7 @@ namespace Umbraco.Web.BackOffice.Controllers
[ValidationFilter]
[AngularJsonOnlyConfiguration] // TODO: This could be applied with our Application Model conventions
[IsBackOffice]
- [UmbracoAuthorize]
+ [UmbracoBackOfficeAuthorize]
public class DashboardController : UmbracoApiController
{
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
diff --git a/src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs b/src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs
index 07e3cb13da..cd320d49ff 100644
--- a/src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs
@@ -64,7 +64,7 @@ namespace Umbraco.Web.BackOffice.Controllers
_viewEngines = viewEngines;
}
- [UmbracoAuthorize(redirectToUmbracoLogin: true, requireApproval : false)]
+ [UmbracoBackOfficeAuthorize(redirectToUmbracoLogin: true, requireApproval : false)]
[DisableBrowserCache]
public ActionResult Index()
{
@@ -107,7 +107,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// The endpoint that is loaded within the preview iframe
///
///
- [UmbracoAuthorize]
+ [UmbracoBackOfficeAuthorize]
public ActionResult Frame(int id, string culture)
{
var user = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser;
diff --git a/src/Umbraco.Web.BackOffice/Controllers/UmbracoAuthorizedApiController.cs b/src/Umbraco.Web.BackOffice/Controllers/UmbracoAuthorizedApiController.cs
index c232401b78..e3d779d61d 100644
--- a/src/Umbraco.Web.BackOffice/Controllers/UmbracoAuthorizedApiController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/UmbracoAuthorizedApiController.cs
@@ -16,7 +16,7 @@ namespace Umbraco.Web.BackOffice.Controllers
///
[IsBackOffice]
[UmbracoUserTimeoutFilter]
- [UmbracoAuthorize]
+ [UmbracoBackOfficeAuthorize]
[DisableBrowserCache]
[UmbracoWebApiRequireHttps]
[CheckIfUserTicketDataIsStale]
diff --git a/src/Umbraco.Web.Common/AspNetCore/UmbracoViewPage.cs b/src/Umbraco.Web.Common/AspNetCore/UmbracoViewPage.cs
index cf41670d8e..4b8f730e45 100644
--- a/src/Umbraco.Web.Common/AspNetCore/UmbracoViewPage.cs
+++ b/src/Umbraco.Web.Common/AspNetCore/UmbracoViewPage.cs
@@ -1,6 +1,7 @@
using System;
using System.Text;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor;
@@ -8,12 +9,12 @@ using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Umbraco.Core;
-using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Strings;
+using Umbraco.Extensions;
using Umbraco.Web.Common.ModelBinders;
namespace Umbraco.Web.Common.AspNetCore
@@ -110,6 +111,8 @@ namespace Umbraco.Web.Common.AspNetCore
ViewData = (ViewDataDictionary) viewData;
}
+
+
// viewData is the ViewDataDictionary (maybe ) that we have
// modelType is the type of the model that we need to bind to
//
@@ -143,5 +146,16 @@ namespace Umbraco.Web.Common.AspNetCore
var nViewData = (ViewDataDictionary)Activator.CreateInstance(nViewDataType, tViewData);
return nViewData;
}
+
+ public HtmlString RenderSection(string name, HtmlString defaultContents)
+ {
+ return RazorPageExtensions.RenderSection(this, name, defaultContents);
+ }
+
+ public HtmlString RenderSection(string name, string defaultContents)
+ {
+ return RazorPageExtensions.RenderSection(this, name, defaultContents);
+ }
+
}
}
diff --git a/src/Umbraco.Web.Common/Constants/ViewConstants.cs b/src/Umbraco.Web.Common/Constants/ViewConstants.cs
index 5da1a74f55..4c87509069 100644
--- a/src/Umbraco.Web.Common/Constants/ViewConstants.cs
+++ b/src/Umbraco.Web.Common/Constants/ViewConstants.cs
@@ -8,5 +8,12 @@
internal const string ViewLocation = "~/Views";
internal const string DataTokenCurrentViewContext = "umbraco-current-view-context";
+
+ internal static class ReservedAdditionalKeys
+ {
+ internal const string Controller = "c";
+ internal const string Action = "a";
+ internal const string Area = "ar";
+ }
}
}
diff --git a/src/Umbraco.Web.Common/Exceptions/HttpUmbracoFormRouteStringException.cs b/src/Umbraco.Web.Common/Exceptions/HttpUmbracoFormRouteStringException.cs
new file mode 100644
index 0000000000..8ba326a926
--- /dev/null
+++ b/src/Umbraco.Web.Common/Exceptions/HttpUmbracoFormRouteStringException.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Runtime.Serialization;
+
+namespace Umbraco.Web.Common.Exceptions
+{
+ ///
+ /// Exception that occurs when an Umbraco form route string is invalid
+ ///
+ [Serializable]
+ public sealed class HttpUmbracoFormRouteStringException : Exception
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public HttpUmbracoFormRouteStringException()
+ { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The that holds the serialized object data about the exception being thrown.
+ /// The that holds the contextual information about the source or destination.
+ private HttpUmbracoFormRouteStringException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The error message displayed to the client when the exception is thrown.
+ public HttpUmbracoFormRouteStringException(string message)
+ : base(message)
+ { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The error message displayed to the client when the exception is thrown.
+ /// The , if any, that threw the current exception.
+ public HttpUmbracoFormRouteStringException(string message, Exception innerException)
+ : base(message, innerException)
+ { }
+ }
+}
diff --git a/src/Umbraco.Web/BlockListTemplateExtensions.cs b/src/Umbraco.Web.Common/Extensions/BlockListTemplateExtensions.cs
similarity index 51%
rename from src/Umbraco.Web/BlockListTemplateExtensions.cs
rename to src/Umbraco.Web.Common/Extensions/BlockListTemplateExtensions.cs
index 6e105a24d6..06c3efaf02 100644
--- a/src/Umbraco.Web/BlockListTemplateExtensions.cs
+++ b/src/Umbraco.Web.Common/Extensions/BlockListTemplateExtensions.cs
@@ -1,30 +1,30 @@
using System;
-using System.Web.Mvc;
-using System.Web.Mvc.Html;
using Umbraco.Core.Models.Blocks;
using Umbraco.Core.Models.PublishedContent;
-using System.Web;
+using Microsoft.AspNetCore.Html;
+using Microsoft.AspNetCore.Mvc.Rendering;
+using Microsoft.AspNetCore.Mvc.ViewFeatures;
-namespace Umbraco.Web
+namespace Umbraco.Extensions
{
public static class BlockListTemplateExtensions
{
public const string DefaultFolder = "BlockList/";
public const string DefaultTemplate = "Default";
- public static IHtmlString GetBlockListHtml(this HtmlHelper html, BlockListModel model, string template = DefaultTemplate)
+ public static IHtmlContent GetBlockListHtml(this HtmlHelper html, BlockListModel model, string template = DefaultTemplate)
{
- if (model?.Count == 0) return new MvcHtmlString(string.Empty);
+ if (model?.Count == 0) return new HtmlString(string.Empty);
var view = DefaultFolder + template;
return html.Partial(view, model);
}
- public static IHtmlString GetBlockListHtml(this HtmlHelper html, IPublishedProperty property, string template = DefaultTemplate) => GetBlockListHtml(html, property?.GetValue() as BlockListModel, template);
+ public static IHtmlContent GetBlockListHtml(this HtmlHelper html, IPublishedProperty property, string template = DefaultTemplate) => GetBlockListHtml(html, property?.GetValue() as BlockListModel, template);
- public static IHtmlString GetBlockListHtml(this HtmlHelper html, IPublishedContent contentItem, string propertyAlias) => GetBlockListHtml(html, contentItem, propertyAlias, DefaultTemplate);
+ public static IHtmlContent GetBlockListHtml(this HtmlHelper html, IPublishedContent contentItem, string propertyAlias) => GetBlockListHtml(html, contentItem, propertyAlias, DefaultTemplate);
- public static IHtmlString GetBlockListHtml(this HtmlHelper html, IPublishedContent contentItem, string propertyAlias, string template)
+ public static IHtmlContent GetBlockListHtml(this HtmlHelper html, IPublishedContent contentItem, string propertyAlias, string template)
{
if (propertyAlias == null) throw new ArgumentNullException(nameof(propertyAlias));
if (string.IsNullOrWhiteSpace(propertyAlias)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(propertyAlias));
diff --git a/src/Umbraco.Web/CacheHelperExtensions.cs b/src/Umbraco.Web.Common/Extensions/CacheHelperExtensions.cs
similarity index 83%
rename from src/Umbraco.Web/CacheHelperExtensions.cs
rename to src/Umbraco.Web.Common/Extensions/CacheHelperExtensions.cs
index e27b0db1fc..e8309262e6 100644
--- a/src/Umbraco.Web/CacheHelperExtensions.cs
+++ b/src/Umbraco.Web.Common/Extensions/CacheHelperExtensions.cs
@@ -1,11 +1,11 @@
using System;
-using System.Web;
-using System.Web.Mvc;
-using System.Web.Mvc.Html;
+using Microsoft.AspNetCore.Html;
+using Microsoft.AspNetCore.Mvc.Rendering;
+using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Umbraco.Core.Cache;
using Umbraco.Core.Hosting;
-namespace Umbraco.Web
+namespace Umbraco.Extensions
{
///
@@ -25,10 +25,10 @@ namespace Umbraco.Web
/// used to cache the partial view, this key could change if it is cached by page or by member
///
///
- public static IHtmlString CachedPartialView(
+ public static IHtmlContent CachedPartialView(
this AppCaches appCaches,
IHostingEnvironment hostingEnvironment,
- HtmlHelper htmlHelper,
+ IHtmlHelper htmlHelper,
string partialViewName,
object model,
int cachedSeconds,
@@ -42,7 +42,7 @@ namespace Umbraco.Web
return htmlHelper.Partial(partialViewName, model, viewData);
}
- return appCaches.RuntimeCache.GetCacheItem(
+ return appCaches.RuntimeCache.GetCacheItem(
Core.CacheHelperExtensions.PartialViewCacheKey + cacheKey,
() => htmlHelper.Partial(partialViewName, model, viewData),
timeout: new TimeSpan(0, 0, 0, cachedSeconds));
diff --git a/src/Umbraco.Web.Common/Extensions/RazorPageExtensions.cs b/src/Umbraco.Web.Common/Extensions/RazorPageExtensions.cs
new file mode 100644
index 0000000000..884e2bbdbc
--- /dev/null
+++ b/src/Umbraco.Web.Common/Extensions/RazorPageExtensions.cs
@@ -0,0 +1,19 @@
+using Microsoft.AspNetCore.Html;
+using Microsoft.AspNetCore.Mvc.Razor;
+
+namespace Umbraco.Extensions
+{
+ public static class RazorPageExtensions
+ {
+ public static HtmlString RenderSection(this RazorPage webPage, string name, HtmlString defaultContents)
+ {
+ return webPage.IsSectionDefined(name) ? webPage.RenderSection(name) : defaultContents;
+ }
+
+ public static HtmlString RenderSection(this RazorPage webPage, string name, string defaultContents)
+ {
+ return webPage.IsSectionDefined(name) ? webPage.RenderSection(name) : new HtmlString(defaultContents);
+ }
+
+ }
+}
diff --git a/src/Umbraco.Web.Common/Extensions/ViewContextExtensions.cs b/src/Umbraco.Web.Common/Extensions/ViewContextExtensions.cs
new file mode 100644
index 0000000000..17a9d048fc
--- /dev/null
+++ b/src/Umbraco.Web.Common/Extensions/ViewContextExtensions.cs
@@ -0,0 +1,75 @@
+using Microsoft.AspNetCore.Mvc.Rendering;
+using Microsoft.AspNetCore.Mvc.ViewFeatures;
+
+namespace Umbraco.Extensions
+{
+ public static class ViewContextExtensions
+ {
+ ///
+ /// Creates a new ViewContext from an existing one but specifies a new Model for the ViewData
+ ///
+ ///
+ ///
+ ///
+ public static ViewContext CopyWithModel(this ViewContext vc, object model)
+ {
+ return new ViewContext
+ {
+ View = vc.View,
+ Writer = vc.Writer,
+ ActionDescriptor = vc.ActionDescriptor,
+ FormContext = vc.FormContext,
+ HttpContext = vc.HttpContext,
+ RouteData = vc.RouteData,
+ TempData = vc.TempData,
+ ViewData = new ViewDataDictionary(vc.ViewData)
+ {
+ Model = model
+ },
+ ClientValidationEnabled = vc.ClientValidationEnabled,
+ ExecutingFilePath = vc.ExecutingFilePath,
+ ValidationMessageElement = vc.ValidationMessageElement,
+ Html5DateRenderingMode = vc.Html5DateRenderingMode,
+ ValidationSummaryMessageElement = vc.ValidationSummaryMessageElement
+ };
+ }
+
+ public static ViewContext Clone(this ViewContext vc)
+ {
+ return new ViewContext
+ {
+ View = vc.View,
+ Writer = vc.Writer,
+ ActionDescriptor = vc.ActionDescriptor,
+ FormContext = vc.FormContext,
+ HttpContext = vc.HttpContext,
+ RouteData = vc.RouteData,
+ TempData = vc.TempData,
+ ViewData = new ViewDataDictionary(vc.ViewData),
+ ClientValidationEnabled = vc.ClientValidationEnabled,
+ ExecutingFilePath = vc.ExecutingFilePath,
+ ValidationMessageElement = vc.ValidationMessageElement,
+ Html5DateRenderingMode = vc.Html5DateRenderingMode,
+ ValidationSummaryMessageElement = vc.ValidationSummaryMessageElement
+ };
+ }
+
+ //public static ViewContext CloneWithWriter(this ViewContext vc, TextWriter writer)
+ //{
+ // return new ViewContext
+ // {
+ // Controller = vc.Controller,
+ // HttpContext = vc.HttpContext,
+ // RequestContext = vc.RequestContext,
+ // RouteData = vc.RouteData,
+ // TempData = vc.TempData,
+ // View = vc.View,
+ // ViewData = vc.ViewData,
+ // FormContext = vc.FormContext,
+ // ClientValidationEnabled = vc.ClientValidationEnabled,
+ // UnobtrusiveJavaScriptEnabled = vc.UnobtrusiveJavaScriptEnabled,
+ // Writer = writer
+ // };
+ //}
+ }
+}
diff --git a/src/Umbraco.Web.Common/Filters/UmbracoAuthorizeAttribute.cs b/src/Umbraco.Web.Common/Filters/UmbracoBackOfficeAuthorizeAttribute.cs
similarity index 66%
rename from src/Umbraco.Web.Common/Filters/UmbracoAuthorizeAttribute.cs
rename to src/Umbraco.Web.Common/Filters/UmbracoBackOfficeAuthorizeAttribute.cs
index 8a7c7b04d5..1f4abbaa25 100644
--- a/src/Umbraco.Web.Common/Filters/UmbracoAuthorizeAttribute.cs
+++ b/src/Umbraco.Web.Common/Filters/UmbracoBackOfficeAuthorizeAttribute.cs
@@ -5,12 +5,12 @@ namespace Umbraco.Web.Common.Filters
///
/// Ensures authorization is successful for a back office user.
///
- public class UmbracoAuthorizeAttribute : TypeFilterAttribute
+ public class UmbracoBackOfficeAuthorizeAttribute : TypeFilterAttribute
{
///
/// Default constructor
///
- public UmbracoAuthorizeAttribute() : this(false, false)
+ public UmbracoBackOfficeAuthorizeAttribute() : this(false, false)
{
}
@@ -20,7 +20,7 @@ namespace Umbraco.Web.Common.Filters
///
///
- public UmbracoAuthorizeAttribute(bool redirectToUmbracoLogin, bool requireApproval) : base(typeof(UmbracoAuthorizeFilter))
+ public UmbracoBackOfficeAuthorizeAttribute(bool redirectToUmbracoLogin, bool requireApproval) : base(typeof(UmbracoBackOfficeAuthorizeFilter))
{
Arguments = new object[] { redirectToUmbracoLogin, requireApproval };
}
@@ -29,7 +29,7 @@ namespace Umbraco.Web.Common.Filters
/// Constructor with redirect url behavior
///
///
- public UmbracoAuthorizeAttribute(string redirectUrl) : base(typeof(UmbracoAuthorizeFilter))
+ public UmbracoBackOfficeAuthorizeAttribute(string redirectUrl) : base(typeof(UmbracoBackOfficeAuthorizeFilter))
{
Arguments = new object[] { redirectUrl };
}
diff --git a/src/Umbraco.Web.Common/Filters/UmbracoAuthorizeFilter.cs b/src/Umbraco.Web.Common/Filters/UmbracoBackOfficeAuthorizeFilter.cs
similarity index 94%
rename from src/Umbraco.Web.Common/Filters/UmbracoAuthorizeFilter.cs
rename to src/Umbraco.Web.Common/Filters/UmbracoBackOfficeAuthorizeFilter.cs
index 66b1462ae9..e7889cd1a8 100644
--- a/src/Umbraco.Web.Common/Filters/UmbracoAuthorizeFilter.cs
+++ b/src/Umbraco.Web.Common/Filters/UmbracoBackOfficeAuthorizeFilter.cs
@@ -13,7 +13,7 @@ namespace Umbraco.Web.Common.Filters
///
/// Ensures authorization is successful for a back office user.
///
- public class UmbracoAuthorizeFilter : IAuthorizationFilter
+ public class UmbracoBackOfficeAuthorizeFilter : IAuthorizationFilter
{
private readonly bool _requireApproval;
@@ -28,7 +28,7 @@ namespace Umbraco.Web.Common.Filters
private readonly bool _redirectToUmbracoLogin;
private string _redirectUrl;
- private UmbracoAuthorizeFilter(
+ private UmbracoBackOfficeAuthorizeFilter(
IHostingEnvironment hostingEnvironment,
IUmbracoContextAccessor umbracoContext,
IRuntimeState runtimeState, LinkGenerator linkGenerator,
@@ -51,7 +51,7 @@ namespace Umbraco.Web.Common.Filters
///
///
///
- public UmbracoAuthorizeFilter(
+ public UmbracoBackOfficeAuthorizeFilter(
IHostingEnvironment hostingEnvironment,
IUmbracoContextAccessor umbracoContext,
IRuntimeState runtimeState, LinkGenerator linkGenerator,
@@ -59,7 +59,7 @@ namespace Umbraco.Web.Common.Filters
{
}
- public UmbracoAuthorizeFilter(
+ public UmbracoBackOfficeAuthorizeFilter(
IHostingEnvironment hostingEnvironment,
IUmbracoContextAccessor umbracoContext,
IRuntimeState runtimeState, LinkGenerator linkGenerator,
diff --git a/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeAttribute.cs b/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeAttribute.cs
new file mode 100644
index 0000000000..cc6058121b
--- /dev/null
+++ b/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeAttribute.cs
@@ -0,0 +1,20 @@
+using Microsoft.AspNetCore.Mvc;
+
+namespace Umbraco.Web.Common.Filters
+{
+ ///
+ /// Ensures authorization is successful for a website user (member).
+ ///
+ public class UmbracoMemberAuthorizeAttribute : TypeFilterAttribute
+ {
+ public UmbracoMemberAuthorizeAttribute() : this(string.Empty, string.Empty, string.Empty)
+ {
+ }
+
+ public UmbracoMemberAuthorizeAttribute(string allowType, string allowGroup, string allowMembers) : base(typeof(UmbracoMemberAuthorizeFilter))
+ {
+ Arguments = new object[] { allowType, allowGroup, allowMembers};
+ }
+
+ }
+}
diff --git a/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs b/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs
new file mode 100644
index 0000000000..27c2922637
--- /dev/null
+++ b/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs
@@ -0,0 +1,69 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Filters;
+using System.Collections.Generic;
+using Umbraco.Core;
+using Umbraco.Extensions;
+
+namespace Umbraco.Web.Common.Filters
+{
+
+ ///
+ /// Ensures authorization is successful for a back office user.
+ ///
+ public class UmbracoMemberAuthorizeFilter : IAuthorizationFilter
+ {
+ ///
+ /// Comma delimited list of allowed member types
+ ///
+ public string AllowType { get; private set;}
+
+ ///
+ /// Comma delimited list of allowed member groups
+ ///
+ public string AllowGroup { get; private set;}
+
+ ///
+ /// Comma delimited list of allowed members
+ ///
+ public string AllowMembers { get; private set; }
+
+
+ private UmbracoMemberAuthorizeFilter(
+ string allowType, string allowGroup, string allowMembers)
+ {
+ AllowType = allowType;
+ AllowGroup = allowGroup;
+ AllowMembers = allowMembers;
+ }
+
+ public void OnAuthorization(AuthorizationFilterContext context)
+ {
+ if (!IsAuthorized())
+ {
+ context.HttpContext.SetReasonPhrase("Resource restricted: either member is not logged on or is not of a permitted type or group.");
+ context.Result = new ForbidResult();
+ }
+ }
+
+ private bool IsAuthorized()
+ {
+ if (AllowMembers.IsNullOrWhiteSpace())
+ AllowMembers = "";
+ if (AllowGroup.IsNullOrWhiteSpace())
+ AllowGroup = "";
+ if (AllowType.IsNullOrWhiteSpace())
+ AllowType = "";
+
+ var members = new List();
+ foreach (var s in AllowMembers.Split(','))
+ {
+ if (int.TryParse(s, out var id))
+ {
+ members.Add(id);
+ }
+ }
+
+ return false;// TODO reintroduce when members are implemented: _memberHelper.IsMemberAuthorized(AllowType.Split(','), AllowGroup.Split(','), members);
+ }
+ }
+}
diff --git a/src/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringAttribute.cs b/src/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringAttribute.cs
new file mode 100644
index 0000000000..45806b9d18
--- /dev/null
+++ b/src/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringAttribute.cs
@@ -0,0 +1,74 @@
+using System;
+using Microsoft.AspNetCore.DataProtection;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Umbraco.Core;
+using Umbraco.Web.Common.Constants;
+using Umbraco.Web.Common.Exceptions;
+using Umbraco.Web.Common.Security;
+
+namespace Umbraco.Web.Common.Filters
+{
+
+ ///
+ /// Attribute used to check that the request contains a valid Umbraco form request string.
+ ///
+ ///
+ /// Applying this attribute/filter to a or SurfaceController Action will ensure that the Action can only be executed
+ /// when it is routed to from within Umbraco, typically when rendering a form with BeginUmbracoForm. It will mean that the natural MVC route for this Action
+ /// will fail with a .
+ ///
+ public class ValidateUmbracoFormRouteStringAttribute : TypeFilterAttribute
+ {
+
+ public ValidateUmbracoFormRouteStringAttribute() : base(typeof(ValidateUmbracoFormRouteStringFilter))
+ {
+ Arguments = new object[] { };
+ }
+
+ internal class ValidateUmbracoFormRouteStringFilter: IAuthorizationFilter
+ {
+ private readonly IDataProtectionProvider _dataProtectionProvider;
+
+ public ValidateUmbracoFormRouteStringFilter(IDataProtectionProvider dataProtectionProvider)
+ {
+ _dataProtectionProvider = dataProtectionProvider;
+ }
+
+ public void OnAuthorization(AuthorizationFilterContext context)
+ {
+ if (context == null) throw new ArgumentNullException(nameof(context));
+
+ var ufprt = context.HttpContext.Request.Form["ufprt"];
+
+ if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
+ {
+ ValidateRouteString(ufprt, controllerActionDescriptor.ControllerName, controllerActionDescriptor.ActionName, context.RouteData?.DataTokens["area"]?.ToString());
+ }
+
+ }
+
+ public void ValidateRouteString(string ufprt, string currentController, string currentAction, string currentArea)
+ {
+ if (ufprt.IsNullOrWhiteSpace())
+ {
+ throw new HttpUmbracoFormRouteStringException("The required request field \"ufprt\" is not present.");
+ }
+
+ if (!EncryptionHelper.DecryptAndValidateEncryptedRouteString(_dataProtectionProvider, ufprt, out var additionalDataParts))
+ {
+ throw new HttpUmbracoFormRouteStringException("The Umbraco form request route string could not be decrypted.");
+ }
+
+ if (!additionalDataParts[ViewConstants.ReservedAdditionalKeys.Controller].InvariantEquals(currentController) ||
+ !additionalDataParts[ViewConstants.ReservedAdditionalKeys.Action].InvariantEquals(currentAction) ||
+ (!additionalDataParts[ViewConstants.ReservedAdditionalKeys.Area].IsNullOrWhiteSpace() && !additionalDataParts[ViewConstants.ReservedAdditionalKeys.Area].InvariantEquals(currentArea)))
+ {
+ throw new HttpUmbracoFormRouteStringException("The provided Umbraco form request route string was meant for a different controller and action.");
+ }
+
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Web/HtmlStringUtilities.cs b/src/Umbraco.Web.Common/Mvc/HtmlStringUtilities.cs
similarity index 97%
rename from src/Umbraco.Web/HtmlStringUtilities.cs
rename to src/Umbraco.Web.Common/Mvc/HtmlStringUtilities.cs
index cbeff72acf..204bb61425 100644
--- a/src/Umbraco.Web/HtmlStringUtilities.cs
+++ b/src/Umbraco.Web.Common/Mvc/HtmlStringUtilities.cs
@@ -5,8 +5,9 @@ using System.Linq;
using System.Text;
using System.Web;
using HtmlAgilityPack;
+using Microsoft.AspNetCore.Html;
-namespace Umbraco.Web
+namespace Umbraco.Web.Common.Mvc
{
///
/// Provides utility methods for UmbracoHelper for working with strings and HTML in views.
@@ -20,7 +21,7 @@ namespace Umbraco.Web
///
/// The HTML encoded text with text line breaks replaced with HTML line breaks (<br />).
///
- public IHtmlString ReplaceLineBreaks(string text)
+ public IHtmlContent ReplaceLineBreaks(string text)
{
var value = HttpUtility.HtmlEncode(text)?
.Replace("\r\n", "
")
@@ -63,7 +64,7 @@ namespace Umbraco.Web
return new HtmlString(doc.DocumentNode.FirstChild.InnerHtml.Replace(" ", " "));
}
- internal string Join(string separator, params object[] args)
+ public string Join(string separator, params object[] args)
{
var results = args
.Where(x => x != null)
@@ -72,7 +73,7 @@ namespace Umbraco.Web
return string.Join(separator, results);
}
- internal string Concatenate(params object[] args)
+ public string Concatenate(params object[] args)
{
var sb = new StringBuilder();
foreach (var arg in args
@@ -85,7 +86,7 @@ namespace Umbraco.Web
return sb.ToString();
}
- internal string Coalesce(params object[] args)
+ public string Coalesce(params object[] args)
{
var arg = args
.Where(x => x != null)
@@ -95,7 +96,7 @@ namespace Umbraco.Web
return arg ?? string.Empty;
}
- public IHtmlString Truncate(string html, int length, bool addElipsis, bool treatTagsAsContent)
+ public IHtmlContent Truncate(string html, int length, bool addElipsis, bool treatTagsAsContent)
{
const string hellip = "…";
diff --git a/src/Umbraco.Web.Common/Security/EncryptionHelper.cs b/src/Umbraco.Web.Common/Security/EncryptionHelper.cs
new file mode 100644
index 0000000000..300afd530d
--- /dev/null
+++ b/src/Umbraco.Web.Common/Security/EncryptionHelper.cs
@@ -0,0 +1,104 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Web;
+using Microsoft.AspNetCore.DataProtection;
+using Microsoft.Extensions.Logging;
+using Umbraco.Core;
+using Umbraco.Web.Common.Constants;
+
+namespace Umbraco.Web.Common.Security
+{
+ public class EncryptionHelper
+ {
+ private static IDataProtector CreateDataProtector(IDataProtectionProvider dataProtectionProvider)
+ {
+ return dataProtectionProvider.CreateProtector(nameof(EncryptionHelper));
+ }
+
+ public static string Decrypt(string encryptedString, IDataProtectionProvider dataProtectionProvider)
+ {
+ return CreateDataProtector(dataProtectionProvider).Unprotect(encryptedString);
+ }
+
+ public static string Encrypt(string plainString, IDataProtectionProvider dataProtectionProvider)
+ {
+ return CreateDataProtector(dataProtectionProvider).Protect(plainString);
+ }
+
+ ///
+ /// This is used in methods like BeginUmbracoForm and SurfaceAction to generate an encrypted string which gets submitted in a request for which
+ /// Umbraco can decrypt during the routing process in order to delegate the request to a specific MVC Controller.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static string CreateEncryptedRouteString(IDataProtectionProvider dataProtectionProvider, string controllerName, string controllerAction, string area, object additionalRouteVals = null)
+ {
+ if (dataProtectionProvider == null) throw new ArgumentNullException(nameof(dataProtectionProvider));
+ if (controllerName == null) throw new ArgumentNullException(nameof(controllerName));
+ if (string.IsNullOrEmpty(controllerName)) throw new ArgumentException("Value can't be empty.", nameof(controllerName));
+ if (controllerAction == null) throw new ArgumentNullException(nameof(controllerAction));
+ if (string.IsNullOrEmpty(controllerAction)) throw new ArgumentException("Value can't be empty.", nameof(controllerAction));
+ if (area == null) throw new ArgumentNullException(nameof(area));
+
+ //need to create a params string as Base64 to put into our hidden field to use during the routes
+ var surfaceRouteParams = $"{ViewConstants.ReservedAdditionalKeys.Controller}={WebUtility.UrlEncode(controllerName)}&{ViewConstants.ReservedAdditionalKeys.Action}={WebUtility.UrlEncode(controllerAction)}&{ViewConstants.ReservedAdditionalKeys.Area}={area}";
+
+ //checking if the additional route values is already a dictionary and convert to querystring
+ string additionalRouteValsAsQuery;
+ if (additionalRouteVals != null)
+ {
+ if (additionalRouteVals is Dictionary additionalRouteValsAsDictionary)
+ additionalRouteValsAsQuery = additionalRouteValsAsDictionary.ToQueryString();
+ else
+ additionalRouteValsAsQuery = additionalRouteVals.ToDictionary
///
///
- public RedirectToUmbracoPageResult(int pageId, IPublishedUrlProvider publishedUrlProvider, IUmbracoContextAccessor umbracoContextAccessor)
+ public RedirectToUmbracoPageResult(Guid key, IPublishedUrlProvider publishedUrlProvider, IUmbracoContextAccessor umbracoContextAccessor)
{
- _pageId = pageId;
+ _key = key;
_publishedUrlProvider = publishedUrlProvider;
_umbracoContextAccessor = umbracoContextAccessor;
}
@@ -78,9 +76,9 @@ namespace Umbraco.Web.Website.ActionResults
///
///
///
- public RedirectToUmbracoPageResult(int pageId, QueryString queryString, IPublishedUrlProvider publishedUrlProvider, IUmbracoContextAccessor umbracoContextAccessor)
+ public RedirectToUmbracoPageResult(Guid key, QueryString queryString, IPublishedUrlProvider publishedUrlProvider, IUmbracoContextAccessor umbracoContextAccessor)
{
- _pageId = pageId;
+ _key = key;
_queryString = queryString;
_publishedUrlProvider = publishedUrlProvider;
_umbracoContextAccessor = umbracoContextAccessor;
@@ -95,7 +93,7 @@ namespace Umbraco.Web.Website.ActionResults
public RedirectToUmbracoPageResult(IPublishedContent publishedContent, IPublishedUrlProvider publishedUrlProvider, IUmbracoContextAccessor umbracoContextAccessor)
{
_publishedContent = publishedContent;
- _pageId = publishedContent.Id;
+ _key = publishedContent.Key;
_publishedUrlProvider = publishedUrlProvider;
_umbracoContextAccessor = umbracoContextAccessor;
}
@@ -110,7 +108,7 @@ namespace Umbraco.Web.Website.ActionResults
public RedirectToUmbracoPageResult(IPublishedContent publishedContent, QueryString queryString, IPublishedUrlProvider publishedUrlProvider, IUmbracoContextAccessor umbracoContextAccessor)
{
_publishedContent = publishedContent;
- _pageId = publishedContent.Id;
+ _key = publishedContent.Key;
_queryString = queryString;
_publishedUrlProvider = publishedUrlProvider;
_umbracoContextAccessor = umbracoContextAccessor;
diff --git a/src/Umbraco.Web/Mvc/SurfaceControllerTypeCollection.cs b/src/Umbraco.Web.Website/Collections/SurfaceControllerTypeCollection.cs
similarity index 87%
rename from src/Umbraco.Web/Mvc/SurfaceControllerTypeCollection.cs
rename to src/Umbraco.Web.Website/Collections/SurfaceControllerTypeCollection.cs
index 59b8adc950..fa888dfe88 100644
--- a/src/Umbraco.Web/Mvc/SurfaceControllerTypeCollection.cs
+++ b/src/Umbraco.Web.Website/Collections/SurfaceControllerTypeCollection.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using Umbraco.Core.Composing;
-namespace Umbraco.Web.Mvc
+namespace Umbraco.Web.Website.Collections
{
public class SurfaceControllerTypeCollection : BuilderCollectionBase
{
diff --git a/src/Umbraco.Web/Mvc/SurfaceControllerTypeCollectionBuilder.cs b/src/Umbraco.Web.Website/Collections/SurfaceControllerTypeCollectionBuilder.cs
similarity index 79%
rename from src/Umbraco.Web/Mvc/SurfaceControllerTypeCollectionBuilder.cs
rename to src/Umbraco.Web.Website/Collections/SurfaceControllerTypeCollectionBuilder.cs
index 03de95c798..892184632d 100644
--- a/src/Umbraco.Web/Mvc/SurfaceControllerTypeCollectionBuilder.cs
+++ b/src/Umbraco.Web.Website/Collections/SurfaceControllerTypeCollectionBuilder.cs
@@ -1,7 +1,7 @@
using Umbraco.Core.Composing;
-using Umbraco.Web.WebApi;
+using Umbraco.Web.Website.Controllers;
-namespace Umbraco.Web.Mvc
+namespace Umbraco.Web.Website.Collections
{
public class SurfaceControllerTypeCollectionBuilder : TypeCollectionBuilderBase
{
diff --git a/src/Umbraco.Web.Website/Controllers/SurfaceController.cs b/src/Umbraco.Web.Website/Controllers/SurfaceController.cs
index 726ce4ab82..8125923ee4 100644
--- a/src/Umbraco.Web.Website/Controllers/SurfaceController.cs
+++ b/src/Umbraco.Web.Website/Controllers/SurfaceController.cs
@@ -48,22 +48,22 @@ namespace Umbraco.Web.Website.Controllers
///
/// Redirects to the Umbraco page with the given id
///
- ///
+ ///
///
- protected RedirectToUmbracoPageResult RedirectToUmbracoPage(int pageId)
+ protected RedirectToUmbracoPageResult RedirectToUmbracoPage(Guid contentKey)
{
- return new RedirectToUmbracoPageResult(pageId, _publishedUrlProvider, UmbracoContextAccessor);
+ return new RedirectToUmbracoPageResult(contentKey, _publishedUrlProvider, UmbracoContextAccessor);
}
///
/// Redirects to the Umbraco page with the given id and passes provided querystring
///
- ///
+ ///
///
///
- protected RedirectToUmbracoPageResult RedirectToUmbracoPage(int pageId, QueryString queryString)
+ protected RedirectToUmbracoPageResult RedirectToUmbracoPage(Guid contentKey, QueryString queryString)
{
- return new RedirectToUmbracoPageResult(pageId, queryString, _publishedUrlProvider, UmbracoContextAccessor);
+ return new RedirectToUmbracoPageResult(contentKey, queryString, _publishedUrlProvider, UmbracoContextAccessor);
}
///
diff --git a/src/Umbraco.Web.Website/Controllers/UmbracoAuthorizedController.cs b/src/Umbraco.Web.Website/Controllers/UmbracoAuthorizedController.cs
index 2b5d7a61da..b2611848df 100644
--- a/src/Umbraco.Web.Website/Controllers/UmbracoAuthorizedController.cs
+++ b/src/Umbraco.Web.Website/Controllers/UmbracoAuthorizedController.cs
@@ -9,7 +9,7 @@ namespace Umbraco.Web.Mvc
/// This controller essentially just uses a global UmbracoAuthorizeAttribute, inheritors that require more granular control over the
/// authorization of each method can use this attribute instead of inheriting from this controller.
///
- [UmbracoAuthorize]
+ [UmbracoBackOfficeAuthorize]
[DisableBrowserCache]
public abstract class UmbracoAuthorizedController : UmbracoController
{
diff --git a/src/Umbraco.Web.Website/Extensions/HtmlContentExtensions.cs b/src/Umbraco.Web.Website/Extensions/HtmlContentExtensions.cs
new file mode 100644
index 0000000000..3b74c39475
--- /dev/null
+++ b/src/Umbraco.Web.Website/Extensions/HtmlContentExtensions.cs
@@ -0,0 +1,17 @@
+using System.Text.Encodings.Web;
+using Microsoft.AspNetCore.Html;
+
+namespace Umbraco.Extensions
+{
+ public static class HtmlContentExtensions
+ {
+ public static string ToHtmlString(this IHtmlContent content)
+ {
+ using (var writer = new System.IO.StringWriter())
+ {
+ content.WriteTo(writer, HtmlEncoder.Default);
+ return writer.ToString();
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs b/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs
similarity index 79%
rename from src/Umbraco.Web/HtmlHelperRenderExtensions.cs
rename to src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs
index eccbe073cb..a48ed435bf 100644
--- a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs
+++ b/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs
@@ -3,35 +3,54 @@ using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
+using System.Text.Encodings.Web;
using System.Web;
-using System.Web.Helpers;
-using System.Web.Mvc;
-using System.Web.Mvc.Html;
-using System.Web.Routing;
+using Microsoft.AspNetCore.Antiforgery;
+using Microsoft.AspNetCore.DataProtection;
+using Microsoft.AspNetCore.Html;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.Rendering;
+using Microsoft.AspNetCore.Mvc.ViewFeatures;
+using Microsoft.AspNetCore.Routing;
+using Microsoft.Extensions.DependencyInjection;
using Umbraco.Core;
-using Umbraco.Core.Configuration;
+using Umbraco.Core.Cache;
using Umbraco.Core.Configuration.Models;
-using Umbraco.Core.Configuration.UmbracoSettings;
+using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
-using Umbraco.Web.Mvc;
-using Umbraco.Web.Security;
-using Current = Umbraco.Web.Composing.Current;
+using Umbraco.Core.Logging;
+using Umbraco.Web;
+using Umbraco.Web.Common.Controllers;
+using Umbraco.Web.Common.Mvc;
+using Umbraco.Web.Common.Security;
+using Umbraco.Web.Website.Collections;
+using Umbraco.Web.Website.Controllers;
-namespace Umbraco.Web
+namespace Umbraco.Extensions
{
///
/// HtmlHelper extensions for use in templates
///
public static class HtmlHelperRenderExtensions
{
+ private static T GetRequiredService(IHtmlHelper htmlHelper)
+ {
+ return GetRequiredService(htmlHelper.ViewContext);
+ }
+
+ private static T GetRequiredService(ViewContext viewContext)
+ {
+ return viewContext.HttpContext.RequestServices.GetRequiredService();
+ }
+
///
/// Renders the markup for the profiler
///
///
///
- public static IHtmlString RenderProfiler(this HtmlHelper helper)
+ public static IHtmlContent RenderProfiler(this IHtmlHelper helper)
{
- return new HtmlString(Current.ProfilerHtml.Render());
+ return new HtmlString(GetRequiredService(helper).Render());
}
///
@@ -43,7 +62,7 @@ namespace Umbraco.Web
///
///
///
- public static MvcHtmlString AreaPartial(this HtmlHelper helper, string partial, string area, object model = null, ViewDataDictionary viewData = null)
+ public static IHtmlContent AreaPartial(this IHtmlHelper helper, string partial, string area, object model = null, ViewDataDictionary viewData = null)
{
var originalArea = helper.ViewContext.RouteData.DataTokens["area"];
helper.ViewContext.RouteData.DataTokens["area"] = area;
@@ -61,23 +80,24 @@ namespace Umbraco.Web
///
/// See: http://issues.umbraco.org/issue/U4-1614
///
- public static MvcHtmlString PreviewBadge(this HtmlHelper helper, IHttpContextAccessor httpContextAccessor, GlobalSettings globalSettings, IIOHelper ioHelper, ContentSettings contentSettings)
+ public static IHtmlContent PreviewBadge(this IHtmlHelper helper, IUmbracoContextAccessor umbracoContextAccessor, IHttpContextAccessor httpContextAccessor, GlobalSettings globalSettings, IIOHelper ioHelper, ContentSettings contentSettings)
{
- if (Current.UmbracoContext.InPreviewMode)
+ var umbrcoContext = umbracoContextAccessor.UmbracoContext;
+ if (umbrcoContext.InPreviewMode)
{
var htmlBadge =
String.Format(contentSettings.PreviewBadge,
ioHelper.ResolveUrl(globalSettings.UmbracoPath),
WebUtility.UrlEncode(httpContextAccessor.GetRequiredHttpContext().Request.Path),
- Current.UmbracoContext.PublishedRequest.PublishedContent.Id);
- return new MvcHtmlString(htmlBadge);
+ umbrcoContext.PublishedRequest.PublishedContent.Id);
+ return new HtmlString(htmlBadge);
}
- return new MvcHtmlString("");
+ return new HtmlString("");
}
- public static IHtmlString CachedPartial(
- this HtmlHelper htmlHelper,
+ public static IHtmlContent CachedPartial(
+ this IHtmlHelper htmlHelper,
string partialViewName,
object model,
int cachedSeconds,
@@ -95,36 +115,50 @@ namespace Umbraco.Web
}
if (cacheByPage)
{
- if (Current.UmbracoContext == null)
+ var umbracoContextAccessor = GetRequiredService(htmlHelper);
+ var umbracoContext = umbracoContextAccessor.UmbracoContext;
+ if (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}-", Current.UmbracoContext.PublishedRequest?.PublishedContent?.Id ?? 0);
+ cacheKey.AppendFormat("{0}-", umbracoContext.PublishedRequest?.PublishedContent?.Id ?? 0);
}
if (cacheByMember)
{
- var helper = Current.MembershipHelper;
- var currentMember = helper.GetCurrentMember();
- cacheKey.AppendFormat("m{0}-", currentMember?.Id ?? 0);
+ //TODO reintroduce when members are migrated
+ throw new NotImplementedException("Reintroduce when members are migrated");
+ // var helper = Current.MembershipHelper;
+ // var currentMember = helper.GetCurrentMember();
+ // cacheKey.AppendFormat("m{0}-", currentMember?.Id ?? 0);
}
if (contextualKeyBuilder != null)
{
var contextualKey = contextualKeyBuilder(model, viewData);
cacheKey.AppendFormat("c{0}-", contextualKey);
}
- return Current.AppCaches.CachedPartialView(Current.HostingEnvironment, htmlHelper, partialViewName, model, cachedSeconds, cacheKey.ToString(), viewData);
+
+ var appCaches = GetRequiredService(htmlHelper);
+ var hostingEnvironment = GetRequiredService(htmlHelper);
+
+ return appCaches.CachedPartialView(hostingEnvironment, htmlHelper, partialViewName, model, cachedSeconds, cacheKey.ToString(), viewData);
}
- public static MvcHtmlString EditorFor(this HtmlHelper htmlHelper, string templateName = "", string htmlFieldName = "", object additionalViewData = null)
- where T : new()
- {
- var model = new T();
- var typedHelper = new HtmlHelper(
- htmlHelper.ViewContext.CopyWithModel(model),
- htmlHelper.ViewDataContainer.CopyWithModel(model));
-
- return typedHelper.EditorFor(x => model, templateName, htmlFieldName, additionalViewData);
- }
+ // public static IHtmlContent EditorFor(this IHtmlHelper htmlHelper, string templateName = "", string htmlFieldName = "", object additionalViewData = null)
+ // where T : new()
+ // {
+ // var model = new T();
+ // htmlHelper.Contextualize(htmlHelper.ViewContext.CopyWithModel(model));
+ //
+ // //
+ // // var typedHelper = new HtmlHelper(htmlHelper.
+ // // htmlHelper.
+ // // ,
+ // // htmlHelper.ViewDataContainer.CopyWithModel(model));
+ //
+ //
+ //
+ // return htmlHelper.EditorForModel(x => model, templateName, htmlFieldName, additionalViewData);
+ // }
///
/// A validation summary that lets you pass in a prefix so that the summary only displays for elements
@@ -136,72 +170,95 @@ namespace Umbraco.Web
///
///
///
- public static MvcHtmlString ValidationSummary(this HtmlHelper htmlHelper,
- string prefix = "",
- bool excludePropertyErrors = false,
- string message = "",
- IDictionary htmlAttributes = null)
+ public static IHtmlContent ValidationSummary(this IHtmlHelper htmlHelper,
+ string prefix = "",
+ bool excludePropertyErrors = false,
+ string message = "",
+ object htmlAttributes = null)
{
if (prefix.IsNullOrWhiteSpace())
{
return htmlHelper.ValidationSummary(excludePropertyErrors, message, htmlAttributes);
}
- //if there's a prefix applied, we need to create a new HTML helper with a filtered ModelState collection so that it only looks for
- //specific model state with the prefix.
- var filteredHtmlHelper = new HtmlHelper(htmlHelper.ViewContext, htmlHelper.ViewDataContainer.FilterContainer(prefix));
- return filteredHtmlHelper.ValidationSummary(excludePropertyErrors, message, htmlAttributes);
- }
- ///
- /// Returns the result of a child action of a strongly typed SurfaceController
- ///
- ///
- ///
- ///
- ///
- public static IHtmlString Action(this HtmlHelper htmlHelper, string actionName)
- where T : SurfaceController
- {
- return htmlHelper.Action(actionName, typeof(T));
- }
- ///
- /// Returns the result of a child action of a SurfaceController
- ///
- ///
- ///
- ///
- ///
- ///
- public static IHtmlString Action(this HtmlHelper htmlHelper, string actionName, Type surfaceType)
- {
- if (actionName == null) throw new ArgumentNullException(nameof(actionName));
- if (string.IsNullOrWhiteSpace(actionName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(actionName));
- if (surfaceType == null) throw new ArgumentNullException(nameof(surfaceType));
- var routeVals = new RouteValueDictionary(new {area = ""});
+ var htmlGenerator = GetRequiredService(htmlHelper);
- var surfaceController = Current.SurfaceControllerTypes.SingleOrDefault(x => x == surfaceType);
- if (surfaceController == null)
- throw new InvalidOperationException("Could not find the surface controller of type " + surfaceType.FullName);
- var metaData = PluginController.GetMetadata(surfaceController);
- if (!metaData.AreaName.IsNullOrWhiteSpace())
+ var viewContext = htmlHelper.ViewContext.Clone();
+ foreach (var key in viewContext.ViewData.Keys.ToArray()){
+ if(!key.StartsWith(prefix)){
+ viewContext.ViewData.Remove(key);
+ }
+ }
+ var tagBuilder = htmlGenerator.GenerateValidationSummary(
+ viewContext,
+ excludePropertyErrors,
+ message,
+ headerTag: null,
+ htmlAttributes: htmlAttributes);
+ if (tagBuilder == null)
{
- //set the area to the plugin area
- if (routeVals.ContainsKey("area"))
- {
- routeVals["area"] = metaData.AreaName;
- }
- else
- {
- routeVals.Add("area", metaData.AreaName);
- }
+ return HtmlString.Empty;
}
- return htmlHelper.Action(actionName, metaData.ControllerName, routeVals);
+ return tagBuilder;
}
+// TODO what to do here? This will be view components right?
+ // ///
+ // /// Returns the result of a child action of a strongly typed SurfaceController
+ // ///
+ // ///
+ // ///
+ // ///
+ // ///
+ // public static IHtmlContent Action(this HtmlHelper htmlHelper, string actionName)
+ // where T : SurfaceController
+ // {
+ // return htmlHelper.Action(actionName, typeof(T));
+ // }
+ //
+
+// TODO what to do here? This will be view components right?
+ // ///
+ // /// Returns the result of a child action of a SurfaceController
+ // ///
+ // ///
+ // ///
+ // ///
+ // ///
+ // ///
+ // public static IHtmlContent Action(this IHtmlHelper htmlHelper, string actionName, Type surfaceType)
+ // {
+ // if (actionName == null) throw new ArgumentNullException(nameof(actionName));
+ // if (string.IsNullOrWhiteSpace(actionName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(actionName));
+ // if (surfaceType == null) throw new ArgumentNullException(nameof(surfaceType));
+ //
+ // var routeVals = new RouteValueDictionary(new {area = ""});
+ //
+ // var surfaceControllerTypeCollection = GetRequiredService(htmlHelper);
+ // var surfaceController = surfaceControllerTypeCollection.SingleOrDefault(x => x == surfaceType);
+ // if (surfaceController == null)
+ // throw new InvalidOperationException("Could not find the surface controller of type " + surfaceType.FullName);
+ // var metaData = PluginController.GetMetadata(surfaceController);
+ // if (!metaData.AreaName.IsNullOrWhiteSpace())
+ // {
+ // //set the area to the plugin area
+ // if (routeVals.ContainsKey("area"))
+ // {
+ // routeVals["area"] = metaData.AreaName;
+ // }
+ // else
+ // {
+ // routeVals.Add("area", metaData.AreaName);
+ // }
+ // }
+ //
+ // return htmlHelper.Action(actionName, metaData.ControllerName, routeVals);
+ // }
+
#region BeginUmbracoForm
///
@@ -213,6 +270,7 @@ namespace Umbraco.Web
/// Creates an UmbracoForm
///
///
+ ///
///
///
///
@@ -220,17 +278,18 @@ namespace Umbraco.Web
///
public UmbracoForm(
ViewContext viewContext,
+ HtmlEncoder htmlEncoder,
string controllerName,
string controllerAction,
string area,
FormMethod method,
object additionalRouteVals = null)
- : base(viewContext)
+ : base(viewContext, htmlEncoder)
{
_viewContext = viewContext;
_method = method;
_controllerName = controllerName;
- _encryptedString = UrlHelperRenderExtensions.CreateEncryptedRouteString(controllerName, controllerAction, area, additionalRouteVals);
+ _encryptedString = EncryptionHelper.CreateEncryptedRouteString(GetRequiredService(viewContext), controllerName, controllerAction, area, additionalRouteVals);
}
@@ -240,7 +299,7 @@ namespace Umbraco.Web
private readonly string _encryptedString;
private readonly string _controllerName;
- protected override void Dispose(bool disposing)
+ protected new void Dispose()
{
if (this._disposed)
return;
@@ -252,13 +311,14 @@ namespace Umbraco.Web
|| _controllerName == "UmbLoginStatus"
|| _controllerName == "UmbLogin")
{
- _viewContext.Writer.Write(AntiForgery.GetHtml().ToString());
+ var antiforgery = _viewContext.HttpContext.RequestServices.GetRequiredService();
+ _viewContext.Writer.Write(antiforgery.GetHtml(_viewContext.HttpContext).ToString());
}
//write out the hidden surface form routes
_viewContext.Writer.Write("");
- base.Dispose(disposing);
+ base.Dispose();
}
}
@@ -594,7 +654,8 @@ namespace Umbraco.Web
var area = "";
- var surfaceController = Current.SurfaceControllerTypes.SingleOrDefault(x => x == surfaceType);
+ var surfaceControllerTypeCollection = GetRequiredService(html);
+ var surfaceController = surfaceControllerTypeCollection.SingleOrDefault(x => x == surfaceType);
if (surfaceController == null)
throw new InvalidOperationException("Could not find the surface controller of type " + surfaceType.FullName);
var metaData = PluginController.GetMetadata(surfaceController);
@@ -706,7 +767,8 @@ namespace Umbraco.Web
if (controllerName == null) throw new ArgumentNullException(nameof(controllerName));
if (string.IsNullOrWhiteSpace(controllerName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(controllerName));
- var formAction = Current.UmbracoContext.OriginalRequestUrl.PathAndQuery;
+ var umbracoContextAccessor = GetRequiredService(html);
+ var formAction = umbracoContextAccessor.UmbracoContext.OriginalRequestUrl.PathAndQuery;
return html.RenderForm(formAction, method, htmlAttributes, controllerName, action, area, additionalRouteVals);
}
@@ -764,89 +826,28 @@ namespace Umbraco.Web
tagBuilder.MergeAttribute("action", formAction);
// method is an explicit parameter, so it takes precedence over the htmlAttributes.
tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), true);
- var traditionalJavascriptEnabled = htmlHelper.ViewContext.ClientValidationEnabled && htmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled == false;
+ var traditionalJavascriptEnabled = htmlHelper.ViewContext.ClientValidationEnabled;
if (traditionalJavascriptEnabled)
{
// forms must have an ID for client validation
- tagBuilder.GenerateId("form" + Guid.NewGuid().ToString("N"));
+ tagBuilder.GenerateId("form" + Guid.NewGuid().ToString("N"), string.Empty);
}
- htmlHelper.ViewContext.Writer.Write(tagBuilder.ToString(TagRenderMode.StartTag));
+ htmlHelper.ViewContext.Writer.Write(tagBuilder.RenderStartTag());
+
+ var htmlEncoder = GetRequiredService(htmlHelper);
//new UmbracoForm:
- var theForm = new UmbracoForm(htmlHelper.ViewContext, surfaceController, surfaceAction, area, method, additionalRouteVals);
+ var theForm = new UmbracoForm(htmlHelper.ViewContext, htmlEncoder, surfaceController, surfaceAction, area, method, additionalRouteVals);
if (traditionalJavascriptEnabled)
{
- htmlHelper.ViewContext.FormContext.FormId = tagBuilder.Attributes["id"];
+ htmlHelper.ViewContext.FormContext.FormData["FormId"] = tagBuilder.Attributes["id"];
}
return theForm;
}
#endregion
- #region Wrap
-
- public static HtmlTagWrapper Wrap(this HtmlHelper html, string tag, string innerText, params IHtmlTagWrapper[] children)
- {
- var item = html.Wrap(tag, innerText, (object)null);
- foreach (var child in children)
- {
- item.AddChild(child);
- }
- return item;
- }
-
- public static HtmlTagWrapper Wrap(this HtmlHelper html, string tag, object inner, object anonymousAttributes, params IHtmlTagWrapper[] children)
- {
- string innerText = null;
- if (inner != null)
- {
- innerText = string.Format("{0}", inner);
- }
- var item = html.Wrap(tag, innerText, anonymousAttributes);
- foreach (var child in children)
- {
- item.AddChild(child);
- }
- return item;
- }
- public static HtmlTagWrapper Wrap(this HtmlHelper html, string tag, object inner)
- {
- string innerText = null;
- if (inner != null)
- {
- innerText = string.Format("{0}", inner);
- }
- return html.Wrap(tag, innerText, (object)null);
- }
-
- public static HtmlTagWrapper Wrap(this HtmlHelper html, string tag, string innerText, object anonymousAttributes, params IHtmlTagWrapper[] children)
- {
- var wrap = new HtmlTagWrapper(tag);
- if (anonymousAttributes != null)
- {
- wrap.ReflectAttributesFromAnonymousType(anonymousAttributes);
- }
- if (!string.IsNullOrWhiteSpace(innerText))
- {
- wrap.AddChild(new HtmlTagWrapperTextNode(innerText));
- }
- foreach (var child in children)
- {
- wrap.AddChild(child);
- }
- return wrap;
- }
-
- public static HtmlTagWrapper Wrap(this HtmlHelper html, bool visible, string tag, string innerText, object anonymousAttributes, params IHtmlTagWrapper[] children)
- {
- var item = html.Wrap(tag, innerText, anonymousAttributes, children);
- item.Visible = visible;
- return item;
- }
-
- #endregion
-
#region If
///
@@ -858,7 +859,7 @@ namespace Umbraco.Web
///
/// The HTML encoded value.
///
- public static IHtmlString If(this HtmlHelper html, bool test, string valueIfTrue)
+ public static IHtmlContent If(this HtmlHelper html, bool test, string valueIfTrue)
{
return If(html, test, valueIfTrue, string.Empty);
}
@@ -873,7 +874,7 @@ namespace Umbraco.Web
///
/// The HTML encoded value.
///
- public static IHtmlString If(this HtmlHelper html, bool test, string valueIfTrue, string valueIfFalse)
+ public static IHtmlContent If(this HtmlHelper html, bool test, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(HttpUtility.HtmlEncode(test ? valueIfTrue : valueIfFalse));
}
@@ -892,7 +893,7 @@ namespace Umbraco.Web
///
/// The HTML encoded text with text line breaks replaced with HTML line breaks (<br />).
///
- public static IHtmlString ReplaceLineBreaks(this HtmlHelper helper, string text)
+ public static IHtmlContent ReplaceLineBreaks(this HtmlHelper helper, string text)
{
return StringUtilities.ReplaceLineBreaks(text);
}
@@ -912,15 +913,17 @@ namespace Umbraco.Web
///
/// Strips all HTML tags from a given string, all contents of the tags will remain.
///
- public static IHtmlString StripHtml(this HtmlHelper helper, IHtmlString html, params string[] tags)
+ public static IHtmlContent StripHtml(this HtmlHelper helper, IHtmlContent html, params string[] tags)
{
return helper.StripHtml(html.ToHtmlString(), tags);
}
+
+
///
/// Strips all HTML tags from a given string, all contents of the tags will remain.
///
- public static IHtmlString StripHtml(this HtmlHelper helper, string html, params string[] tags)
+ public static IHtmlContent StripHtml(this HtmlHelper helper, string html, params string[] tags)
{
return StringUtilities.StripHtmlTags(html, tags);
}
@@ -952,7 +955,7 @@ namespace Umbraco.Web
///
/// Truncates a string to a given length, can add a ellipsis at the end (...). Method checks for open HTML tags, and makes sure to close them
///
- public static IHtmlString Truncate(this HtmlHelper helper, IHtmlString html, int length)
+ public static IHtmlContent Truncate(this HtmlHelper helper, IHtmlContent html, int length)
{
return helper.Truncate(html.ToHtmlString(), length, true, false);
}
@@ -960,7 +963,7 @@ namespace Umbraco.Web
///
/// Truncates a string to a given length, can add a ellipsis at the end (...). Method checks for open HTML tags, and makes sure to close them
///
- public static IHtmlString Truncate(this HtmlHelper helper, IHtmlString html, int length, bool addElipsis)
+ public static IHtmlContent Truncate(this HtmlHelper helper, IHtmlContent html, int length, bool addElipsis)
{
return helper.Truncate(html.ToHtmlString(), length, addElipsis, false);
}
@@ -968,7 +971,7 @@ namespace Umbraco.Web
///
/// Truncates a string to a given length, can add a ellipsis at the end (...). Method checks for open HTML tags, and makes sure to close them
///
- public static IHtmlString Truncate(this HtmlHelper helper, IHtmlString html, int length, bool addElipsis, bool treatTagsAsContent)
+ public static IHtmlContent Truncate(this HtmlHelper helper, IHtmlContent html, int length, bool addElipsis, bool treatTagsAsContent)
{
return helper.Truncate(html.ToHtmlString(), length, addElipsis, treatTagsAsContent);
}
@@ -976,7 +979,7 @@ namespace Umbraco.Web
///
/// Truncates a string to a given length, can add a ellipsis at the end (...). Method checks for open HTML tags, and makes sure to close them
///
- public static IHtmlString Truncate(this HtmlHelper helper, string html, int length)
+ public static IHtmlContent Truncate(this HtmlHelper helper, string html, int length)
{
return helper.Truncate(html, length, true, false);
}
@@ -984,7 +987,7 @@ namespace Umbraco.Web
///
/// Truncates a string to a given length, can add a ellipsis at the end (...). Method checks for open HTML tags, and makes sure to close them
///
- public static IHtmlString Truncate(this HtmlHelper helper, string html, int length, bool addElipsis)
+ public static IHtmlContent Truncate(this HtmlHelper helper, string html, int length, bool addElipsis)
{
return helper.Truncate(html, length, addElipsis, false);
}
@@ -992,7 +995,7 @@ namespace Umbraco.Web
///
/// Truncates a string to a given length, can add a ellipsis at the end (...). Method checks for open HTML tags, and makes sure to close them
///
- public static IHtmlString Truncate(this HtmlHelper helper, string html, int length, bool addElipsis, bool treatTagsAsContent)
+ public static IHtmlContent Truncate(this HtmlHelper helper, string html, int length, bool addElipsis, bool treatTagsAsContent)
{
return StringUtilities.Truncate(html, length, addElipsis, treatTagsAsContent);
}
@@ -1002,7 +1005,7 @@ namespace Umbraco.Web
///
/// Truncates a string to a given amount of words, can add a ellipsis at the end (...). Method checks for open HTML tags, and makes sure to close them
///
- public static IHtmlString TruncateByWords(this HtmlHelper helper, string html, int words)
+ public static IHtmlContent TruncateByWords(this HtmlHelper helper, string html, int words)
{
int length = StringUtilities.WordsToLength(html, words);
@@ -1012,7 +1015,7 @@ namespace Umbraco.Web
///
/// Truncates a string to a given amount of words, can add a ellipsis at the end (...). Method checks for open HTML tags, and makes sure to close them
///
- public static IHtmlString TruncateByWords(this HtmlHelper helper, string html, int words, bool addElipsis)
+ public static IHtmlContent TruncateByWords(this HtmlHelper helper, string html, int words, bool addElipsis)
{
int length = StringUtilities.WordsToLength(html, words);
@@ -1022,7 +1025,7 @@ namespace Umbraco.Web
///
/// Truncates a string to a given amount of words, can add a ellipsis at the end (...). Method checks for open HTML tags, and makes sure to close them
///
- public static IHtmlString TruncateByWords(this HtmlHelper helper, IHtmlString html, int words)
+ public static IHtmlContent TruncateByWords(this HtmlHelper helper, IHtmlContent html, int words)
{
int length = StringUtilities.WordsToLength(html.ToHtmlString(), words);
@@ -1032,7 +1035,7 @@ namespace Umbraco.Web
///
/// Truncates a string to a given amount of words, can add a ellipsis at the end (...). Method checks for open HTML tags, and makes sure to close them
///
- public static IHtmlString TruncateByWords(this HtmlHelper helper, IHtmlString html, int words, bool addElipsis)
+ public static IHtmlContent TruncateByWords(this HtmlHelper helper, IHtmlContent html, int words, bool addElipsis)
{
int length = StringUtilities.WordsToLength(html.ToHtmlString(), words);
diff --git a/src/Umbraco.Web.Website/Extensions/TypeLoaderExtensions.cs b/src/Umbraco.Web.Website/Extensions/TypeLoaderExtensions.cs
new file mode 100644
index 0000000000..c01bdf7804
--- /dev/null
+++ b/src/Umbraco.Web.Website/Extensions/TypeLoaderExtensions.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using Umbraco.Core.Composing;
+using Umbraco.Web.Common.Controllers;
+using Umbraco.Web.Website.Controllers;
+
+
+namespace Umbraco.Extensions
+{
+ ///
+ /// Provides extension methods for the class.
+ ///
+ // Migrated to .NET Core
+ public static class TypeLoaderExtensions
+ {
+ ///
+ /// Gets all types implementing .
+ ///
+ internal static IEnumerable GetSurfaceControllers(this TypeLoader typeLoader)
+ => typeLoader.GetTypes();
+
+ ///
+ /// Gets all types implementing .
+ ///
+ internal static IEnumerable GetUmbracoApiControllers(this TypeLoader typeLoader)
+ => typeLoader.GetTypes();
+ }
+}
diff --git a/src/Umbraco.Web.Website/Extensions/UmbracoWebstiteServiceCollectionExtensions.cs b/src/Umbraco.Web.Website/Extensions/UmbracoWebstiteServiceCollectionExtensions.cs
index b47679a1bf..a5d729f20f 100644
--- a/src/Umbraco.Web.Website/Extensions/UmbracoWebstiteServiceCollectionExtensions.cs
+++ b/src/Umbraco.Web.Website/Extensions/UmbracoWebstiteServiceCollectionExtensions.cs
@@ -25,6 +25,8 @@ namespace Umbraco.Extensions
// Wraps all existing view engines in a ProfilerViewEngine
services.AddTransient, ProfilingViewEngineWrapperMvcViewOptionsSetup>();
+ //TODO figure out if we need more to work on load balanced setups
+ services.AddDataProtection();
}
}
diff --git a/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs b/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs
index 11204483bd..3cbb24b0e0 100644
--- a/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs
+++ b/src/Umbraco.Web.Website/Runtime/WebsiteComposer.cs
@@ -3,6 +3,7 @@ using Umbraco.Core.Composing;
using Umbraco.Extensions;
using Umbraco.Web.Website.Routing;
using Umbraco.Web.Common.Runtime;
+using Umbraco.Web.Website.Collections;
namespace Umbraco.Web.Website.Runtime
{
@@ -19,6 +20,10 @@ namespace Umbraco.Web.Website.Runtime
.ComposeWebsiteUmbracoControllers()
//.SetDefaultRenderMvcController()// default controller for template views
;
+
+
+ composition.WithCollectionBuilder()
+ .Add(composition.TypeLoader.GetSurfaceControllers());
}
}
}
diff --git a/src/Umbraco.Web.Website/UmbracoHelper.cs b/src/Umbraco.Web.Website/UmbracoHelper.cs
new file mode 100644
index 0000000000..d44ca4e5fe
--- /dev/null
+++ b/src/Umbraco.Web.Website/UmbracoHelper.cs
@@ -0,0 +1,445 @@
+using System;
+using System.Collections.Generic;
+using System.Xml.XPath;
+using Umbraco.Core;
+using Umbraco.Core.Dictionary;
+using Umbraco.Core.Models.PublishedContent;
+using Umbraco.Core.Templates;
+using Umbraco.Core.Strings;
+using Umbraco.Core.Xml;
+
+namespace Umbraco.Web.Website
+{
+ ///
+ /// A helper class that provides many useful methods and functionality for using Umbraco in templates
+ ///
+ ///
+ /// This object is a request based lifetime
+ ///
+ public class UmbracoHelper
+ {
+ private readonly IPublishedContentQuery _publishedContentQuery;
+ private readonly IUmbracoComponentRenderer _componentRenderer;
+ private readonly ICultureDictionaryFactory _cultureDictionaryFactory;
+
+ private IPublishedContent _currentPage;
+ private ICultureDictionary _cultureDictionary;
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// The item assigned to the helper.
+ ///
+ ///
+ ///
+ /// Sets the current page to the context's published content request's content item.
+ public UmbracoHelper(IPublishedContent currentPage,
+ ICultureDictionaryFactory cultureDictionary,
+ IUmbracoComponentRenderer componentRenderer,
+ IPublishedContentQuery publishedContentQuery)
+ {
+ _cultureDictionaryFactory = cultureDictionary ?? throw new ArgumentNullException(nameof(cultureDictionary));
+ _componentRenderer = componentRenderer ?? throw new ArgumentNullException(nameof(componentRenderer));
+ _publishedContentQuery = publishedContentQuery ?? throw new ArgumentNullException(nameof(publishedContentQuery));
+ _currentPage = currentPage;
+ }
+
+ ///
+ /// Initializes a new empty instance of .
+ ///
+ /// For tests - nothing is initialized.
+ internal UmbracoHelper()
+ { }
+
+ #endregion
+
+
+ ///
+ /// Gets (or sets) the current item assigned to the UmbracoHelper.
+ ///
+ ///
+ ///
+ /// Note that this is the assigned IPublishedContent item to the
+ /// UmbracoHelper, this is not necessarily the Current IPublishedContent
+ /// item being rendered that is assigned to the UmbracoContext.
+ /// This IPublishedContent object is contextual to the current UmbracoHelper instance.
+ ///
+ ///
+ /// In some cases accessing this property will throw an exception if
+ /// there is not IPublishedContent assigned to the Helper this will
+ /// only ever happen if the Helper is constructed via DI during a non front-end request.
+ ///
+ ///
+ /// Thrown if the
+ /// UmbracoHelper is constructed with an UmbracoContext and it is not a
+ /// front-end request.
+ public IPublishedContent AssignedContentItem
+ {
+ get
+ {
+ if (_currentPage != null)
+ {
+ return _currentPage;
+ }
+
+ throw new InvalidOperationException(
+ $"Cannot return the {nameof(IPublishedContent)} because the {nameof(UmbracoHelper)} was not constructed with an {nameof(IPublishedContent)}."
+ );
+
+ }
+ set => _currentPage = value;
+ }
+
+ ///
+ /// Renders the template for the specified pageId and an optional altTemplateId
+ ///
+ ///
+ /// If not specified, will use the template assigned to the node
+ ///
+ public IHtmlEncodedString RenderTemplate(int contentId, int? altTemplateId = null)
+ {
+ return _componentRenderer.RenderTemplate(contentId, altTemplateId);
+ }
+
+ #region RenderMacro
+
+ ///
+ /// Renders the macro with the specified alias.
+ ///
+ /// The alias.
+ ///
+ public IHtmlEncodedString RenderMacro(string alias)
+ {
+ return _componentRenderer.RenderMacro(AssignedContentItem?.Id ?? 0, alias, null);
+ }
+
+ ///
+ /// Renders the macro with the specified alias, passing in the specified parameters.
+ ///
+ /// The alias.
+ /// The parameters.
+ ///
+ public IHtmlEncodedString RenderMacro(string alias, object parameters)
+ {
+ return _componentRenderer.RenderMacro(AssignedContentItem?.Id ?? 0, alias, parameters?.ToDictionary
[UmbracoRequireHttps]
- [DisableBrowserCache]
+ // [DisableBrowserCache]
public class BackOfficeController : Controller
{
private BackOfficeOwinUserManager _userManager;
diff --git a/src/Umbraco.Web/Mvc/ActionExecutedEventArgs.cs b/src/Umbraco.Web/Mvc/ActionExecutedEventArgs.cs
deleted file mode 100644
index 6904aa103a..0000000000
--- a/src/Umbraco.Web/Mvc/ActionExecutedEventArgs.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System;
-using System.Web.Mvc;
-
-namespace Umbraco.Web.Mvc
-{
- /// Migrated already to .Net Core
- public class ActionExecutedEventArgs : EventArgs
- {
- public Controller Controller { get; set; }
- public object Model { get; set; }
-
- public ActionExecutedEventArgs(Controller controller, object model)
- {
- Controller = controller;
- Model = model;
- }
- }
-}
diff --git a/src/Umbraco.Web/Mvc/AdminTokenAuthorizeAttribute.cs b/src/Umbraco.Web/Mvc/AdminTokenAuthorizeAttribute.cs
deleted file mode 100644
index 25a2f958f8..0000000000
--- a/src/Umbraco.Web/Mvc/AdminTokenAuthorizeAttribute.cs
+++ /dev/null
@@ -1,127 +0,0 @@
-using System;
-using System.Net.Http.Headers;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Web;
-using System.Web.Mvc;
-using Microsoft.Extensions.Logging;
-using Umbraco.Core;
-using Umbraco.Core.Services;
-using Umbraco.Web.Composing;
-
-namespace Umbraco.Web.Mvc
-{
- ///
- /// Used for authorizing scheduled tasks
- ///
- public sealed class AdminTokenAuthorizeAttribute : AuthorizeAttribute
- {
- // see note in HttpInstallAuthorizeAttribute
- private readonly IUserService _userService;
- private readonly IRuntimeState _runtimeState;
- private readonly ILogger _logger;
-
- private IUserService UserService => _userService ?? Current.Services.UserService;
-
- private IRuntimeState RuntimeState => _runtimeState ?? Current.RuntimeState;
-
- private ILogger Logger => _logger ?? Current.Logger;
-
- ///
- /// THIS SHOULD BE ONLY USED FOR UNIT TESTS
- ///
- ///
- ///
- public AdminTokenAuthorizeAttribute(IUserService userService, IRuntimeState runtimeState)
- {
- if (userService == null) throw new ArgumentNullException(nameof(userService));
- if (runtimeState == null) throw new ArgumentNullException(nameof(runtimeState));
- _userService = userService;
- _runtimeState = runtimeState;
- }
-
- public AdminTokenAuthorizeAttribute()
- { }
-
- public const string AuthorizationType = "AToken";
-
- ///
- /// Used to return the full value that needs to go in the Authorization header
- ///
- ///
- ///
- public static string GetAuthHeaderTokenVal(IUserService userService)
- {
- return $"{AuthorizationType} {GetAuthHeaderVal(userService)}";
- }
-
- public static AuthenticationHeaderValue GetAuthenticationHeaderValue(IUserService userService)
- {
- return new AuthenticationHeaderValue(AuthorizationType, GetAuthHeaderVal(userService));
- }
-
- private static string GetAuthHeaderVal(IUserService userService)
- {
- var admin = userService.GetUserById(Core.Constants.Security.SuperUserId);
-
- var token = $"{admin.Email}u____u{admin.Username}u____u{admin.RawPasswordValue}";
-
- var encrypted = token.EncryptWithMachineKey();
- var bytes = Encoding.UTF8.GetBytes(encrypted);
- var base64 = Convert.ToBase64String(bytes);
- return $"val=\"{base64}\"";
- }
-
- ///
- /// Ensures that the user must be in the Administrator or the Install role
- ///
- ///
- ///
- protected override bool AuthorizeCore(HttpContextBase httpContext)
- {
- if (httpContext == null) throw new ArgumentNullException(nameof(httpContext));
-
- // we need to that the app is configured and that a user is logged in
- if (RuntimeState.Level != RuntimeLevel.Run) return false;
-
- // need the auth header
- if (httpContext.Request.Headers["Authorization"] == null || httpContext.Request.Headers["Authorization"].IsNullOrWhiteSpace()) return false;
-
- var header = httpContext.Request.Headers["Authorization"];
- if (header.StartsWith("AToken ") == false) return false;
-
- var keyVal = Regex.Matches(header, "AToken val=(.*?)(?:$|\\s)");
- if (keyVal.Count != 1) return false;
- if (keyVal[0].Groups.Count != 2) return false;
-
- var admin = UserService.GetUserById(Core.Constants.Security.SuperUserId);
- if (admin == null) return false;
-
- try
- {
- //get the token value from the header
- var val = keyVal[0].Groups[1].Value.Trim("\"");
- //un-base 64 the string
- var bytes = Convert.FromBase64String(val);
- var encrypted = Encoding.UTF8.GetString(bytes);
- //decrypt the string
- var text = encrypted.DecryptWithMachineKey();
-
- //split - some users have not set an email, don't strip out empty entries
- var split = text.Split(new[] {"u____u"}, StringSplitOptions.None);
- if (split.Length != 3) return false;
-
- //compare
- return
- split[0] == admin.Email
- && split[1] == admin.Username
- && split[2] == admin.RawPasswordValue;
- }
- catch (Exception ex)
- {
- Logger.LogError(ex, "Failed to format passed in token value");
- return false;
- }
- }
- }
-}
diff --git a/src/Umbraco.Web/Mvc/BackOfficeArea.cs b/src/Umbraco.Web/Mvc/BackOfficeArea.cs
deleted file mode 100644
index eeb48c3b38..0000000000
--- a/src/Umbraco.Web/Mvc/BackOfficeArea.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using System.Web.Mvc;
-using Umbraco.Core.Configuration;
-using Umbraco.Core.Configuration.Models;
-using Umbraco.Core.Hosting;
-using Umbraco.Web.Editors;
-
-namespace Umbraco.Web.Mvc
-{
- // TODO: This has been ported to netcore, can be removed
- internal class BackOfficeArea : AreaRegistration
- {
- private readonly GlobalSettings _globalSettings;
- private readonly IHostingEnvironment _hostingEnvironment;
-
- public BackOfficeArea(GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment)
- {
- _globalSettings = globalSettings;
- _hostingEnvironment = hostingEnvironment;
- }
-
- ///
- /// Create the routes for the area
- ///
- ///
- ///
- /// By using the context to register the routes it means that the area is already applied to them all
- /// and that the namespaces searched for the controllers are ONLY the ones specified.
- ///
- public override void RegisterArea(AreaRegistrationContext context)
- {
-
- context.MapRoute(
- "Umbraco_preview",
- AreaName + "/preview/{action}/{editor}",
- new {controller = "Preview", action = "Index", editor = UrlParameter.Optional},
- new[] { "Umbraco.Web.Editors" });
-
- context.MapRoute(
- "Umbraco_back_office",
- AreaName + "/{action}/{id}",
- new {controller = "BackOffice", action = "Default", id = UrlParameter.Optional},
- //limit the action/id to only allow characters - this is so this route doesn't hog all other
- // routes like: /umbraco/channels/word.aspx, etc...
- new
- {
- action = @"[a-zA-Z]*",
- id = @"[a-zA-Z]*"
- },
- new[] {typeof (BackOfficeController).Namespace});
- }
-
- public override string AreaName => _globalSettings.GetUmbracoMvcArea(_hostingEnvironment);
- }
-}
diff --git a/src/Umbraco.Web/Mvc/Constants.cs b/src/Umbraco.Web/Mvc/Constants.cs
deleted file mode 100644
index c71ed6b104..0000000000
--- a/src/Umbraco.Web/Mvc/Constants.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace Umbraco.Web.Mvc
-{
- ///
- /// constants
- ///
- /// Migrated already to .Net Core
- internal static class Constants
- {
- internal const string ViewLocation = "~/Views";
-
- internal const string DataTokenCurrentViewContext = "umbraco-current-view-context";
- }
-}
diff --git a/src/Umbraco.Web/Mvc/DisableBrowserCacheAttribute.cs b/src/Umbraco.Web/Mvc/DisableBrowserCacheAttribute.cs
deleted file mode 100644
index 567e9ca145..0000000000
--- a/src/Umbraco.Web/Mvc/DisableBrowserCacheAttribute.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using System;
-using System.Web;
-using System.Web.Mvc;
-
-namespace Umbraco.Web.Mvc
-{
- ///
- /// Ensures that the request is not cached by the browser
- ///
- public class DisableBrowserCacheAttribute : ActionFilterAttribute
- {
- public override void OnResultExecuting(ResultExecutingContext filterContext)
- {
- base.OnResultExecuting(filterContext);
-
- // could happens if exception (but AFAIK this wouldn't happen in MVC)
- if (filterContext.HttpContext == null || filterContext.HttpContext.Response == null ||
- filterContext.HttpContext.Response.Cache == null)
- {
- return;
- }
-
- if (filterContext.IsChildAction)
- {
- return;
- }
-
- if (filterContext.HttpContext.Response.StatusCode != 200)
- {
- return;
- }
-
- filterContext.HttpContext.Response.Cache.SetLastModified(DateTime.Now);
- filterContext.HttpContext.Response.Cache.SetValidUntilExpires(false);
- filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
- filterContext.HttpContext.Response.Cache.SetMaxAge(TimeSpan.Zero);
- filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
- filterContext.HttpContext.Response.Cache.SetNoStore();
- filterContext.HttpContext.Response.AddHeader("Pragma", "no-cache");
- filterContext.HttpContext.Response.Cache.SetExpires(new DateTime(1990, 1, 1, 0, 0, 0));
- }
- }
-}
diff --git a/src/Umbraco.Web/Mvc/HtmlTagWrapper.cs b/src/Umbraco.Web/Mvc/HtmlTagWrapper.cs
deleted file mode 100644
index 518121eef9..0000000000
--- a/src/Umbraco.Web/Mvc/HtmlTagWrapper.cs
+++ /dev/null
@@ -1,212 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using System.Web.UI;
-using System.IO;
-using System.Web;
-using Umbraco.Core;
-
-namespace Umbraco.Web.Mvc
-{
- public class HtmlTagWrapper : IHtmlTagWrapper, IHtmlString
- {
- public HtmlTagWrapper Parent;
-
- private readonly List _children;
- public IEnumerable Children
- {
- get { return _children; }
- }
-
- private List> _attributes;
- public IEnumerable> Attributes
- {
- get { return _attributes; }
- }
-
- public void ReflectAttributesFromAnonymousType(List> newAttributes)
- {
- List> mergedAttributes =
- newAttributes
- .Concat(Attributes)
- .GroupBy(kvp => kvp.Key, kvp => kvp.Value)
- .Select(g => new KeyValuePair(g.Key, string.Join(" ", g.ToArray())))
- .ToList();
-
- _attributes = mergedAttributes;
- }
- public void ReflectAttributesFromAnonymousType(object anonymousAttributes)
- {
- var newAttributes =
- anonymousAttributes
- .GetType()
- .GetProperties()
- .Where(prop => !string.IsNullOrWhiteSpace(string.Format("{0}", prop.GetValue(anonymousAttributes, null))))
- .ToList()
- .ConvertAll(prop =>
- new KeyValuePair(
- prop.Name,
- string.Format("{0}", prop.GetValue(anonymousAttributes, null))
- )
- );
- ReflectAttributesFromAnonymousType(newAttributes);
-
- }
-
- public List CssClasses;
- public string Tag;
- public bool Visible;
-
- public HtmlTagWrapper(string tag)
- {
- this.Tag = tag;
- this._children = new List();
- this.CssClasses = new List();
- this._attributes = new List>();
- this.Visible = true;
- }
- public HtmlString Write()
- {
- if ((Children.Any() || Attributes.Any() || CssClasses.Count > 0) && Visible)
- {
- using (MemoryStream ms = new MemoryStream())
- {
- using (TextWriter tw = new StreamWriter(ms))
- {
- HtmlTextWriter html = new HtmlTextWriter(tw);
- this.WriteToHtmlTextWriter(html);
- tw.Flush();
- ms.Position = 0;
- using (TextReader tr = new StreamReader(ms))
- {
- string result = tr.ReadToEnd();
- return new HtmlString(result);
- }
- }
- }
- }
- return new HtmlString(string.Empty);
- }
- public override string ToString()
- {
- return "Use @item.Write() to emit the HTML rather than @item";
- }
- public IHtmlString ToHtml()
- {
- return this.Write();
- }
- public void WriteToHtmlTextWriter(HtmlTextWriter html)
- {
- html.WriteBeginTag(Tag);
- string cssClassNames = string.Join(" ", CssClasses.ToArray()).Trim();
- foreach (var attribute in Attributes)
- {
- html.WriteAttribute(attribute.Key, attribute.Value);
- }
- if (!string.IsNullOrWhiteSpace(cssClassNames))
- {
- html.WriteAttribute("class", cssClassNames);
- }
- html.Write(HtmlTextWriter.TagRightChar);
- foreach (var child in Children)
- {
- child.WriteToHtmlTextWriter(html);
- }
- html.WriteEndTag(Tag);
- }
-
- public HtmlTagWrapper AddClassName(string className)
- {
- className = className.Trim();
- if (!this.CssClasses.Contains(className))
- {
- this.CssClasses.Add(className);
- }
- return this;
- }
-
- public HtmlTagWrapper RemoveClassName(string className)
- {
- className = className.Trim();
- if (this.CssClasses.Contains(className))
- {
- this.CssClasses.Remove(className);
- }
- return this;
- }
-
- public bool HasClassName(string className)
- {
- className = className.Trim();
- return (this.CssClasses.Contains(className));
- }
-
- public HtmlTagWrapper Attr(object newAttributes)
- {
- this.ReflectAttributesFromAnonymousType(newAttributes);
- return this;
- }
- public HtmlTagWrapper Attr(string name, string value)
- {
- if (!string.IsNullOrWhiteSpace(value))
- {
- var newAttributes = new List> {new KeyValuePair(name, value)};
- this.ReflectAttributesFromAnonymousType(newAttributes);
- }
- else
- {
- var existingKey = this._attributes.Find(item => item.Key == name);
- _attributes.Remove(existingKey);
- }
- return this;
- }
-
- public HtmlTagWrapper AddChild(IHtmlTagWrapper newChild)
- {
- _children.Add(newChild);
- return this;
- }
- public HtmlTagWrapper AddChildren(params IHtmlTagWrapper[] collection)
- {
- _children.AddRange(collection);
- return this;
- }
- public HtmlTagWrapper AddChild(string text)
- {
- _children.Add(new HtmlTagWrapperTextNode(text));
- return this;
- }
- public HtmlTagWrapper AddChildAt(int index, IHtmlTagWrapper newChild)
- {
- _children.Insert(index, newChild);
- return this;
- }
- public HtmlTagWrapper AddChildAt(int index, string text)
- {
- _children.Insert(index, new HtmlTagWrapperTextNode(text));
- return this;
- }
- public HtmlTagWrapper AddChildrenAt(int index, params IHtmlTagWrapper[] collection)
- {
- _children.InsertRange(index, collection);
- return this;
- }
- public HtmlTagWrapper RemoveChildAt(int index)
- {
- return this;
- }
- public int CountChildren()
- {
- return this.Children.Count();
- }
- public HtmlTagWrapper ClearChildren()
- {
- return this;
- }
-
- public string ToHtmlString()
- {
- return this.Write().ToHtmlString();
- }
- }
-
-}
diff --git a/src/Umbraco.Web/Mvc/HtmlTagWrapperTextNode.cs b/src/Umbraco.Web/Mvc/HtmlTagWrapperTextNode.cs
deleted file mode 100644
index 1085c2a279..0000000000
--- a/src/Umbraco.Web/Mvc/HtmlTagWrapperTextNode.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Umbraco.Core;
-
-namespace Umbraco.Web.Mvc
-{
- public class HtmlTagWrapperTextNode : IHtmlTagWrapper
- {
- public string Content { get; private set; }
- public HtmlTagWrapperTextNode(string content)
- {
- this.Content = content;
- }
-
- public void WriteToHtmlTextWriter(System.Web.UI.HtmlTextWriter html)
- {
- html.WriteEncodedText(Content);
- }
- }
-}
diff --git a/src/Umbraco.Web/Mvc/IHtmlTagWrapper.cs b/src/Umbraco.Web/Mvc/IHtmlTagWrapper.cs
deleted file mode 100644
index 1c0ff9ca47..0000000000
--- a/src/Umbraco.Web/Mvc/IHtmlTagWrapper.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using System.Web.UI;
-
-namespace Umbraco.Web.Mvc
-{
- public interface IHtmlTagWrapper
- {
- void WriteToHtmlTextWriter(HtmlTextWriter html);
- }
-}
diff --git a/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs b/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs
index 503ea59550..18e1fb8a1a 100644
--- a/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs
+++ b/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs
@@ -124,102 +124,5 @@ namespace Umbraco.Web.Mvc
_contentSettings = contentSettings.Value;
}
- // view logic below:
-
- ///
- /// Ensure that the current view context is added to the route data tokens so we can extract it if we like
- ///
- ///
- /// Currently this is required by mvc macro engines
- ///
- protected override void InitializePage()
- {
- base.InitializePage();
-
- if (ViewContext.IsChildAction) return;
-
- // this is used purely for partial view macros that contain forms and mostly
- // just when rendered within the RTE - this should already be set with the
- // EnsurePartialViewMacroViewContextFilterAttribute
- if (ViewContext.RouteData.DataTokens.ContainsKey(Constants.DataTokenCurrentViewContext) == false)
- ViewContext.RouteData.DataTokens.Add(Constants.DataTokenCurrentViewContext, ViewContext);
- }
-
- ///
- /// This will detect the end /body tag and insert the preview badge if in preview mode
- ///
- ///
- public override void WriteLiteral(object value)
- {
- // filter / add preview banner
- if (Response.ContentType.InvariantEquals("text/html")) // ASP.NET default value
- {
- if (Current.UmbracoContext.IsDebug || Current.UmbracoContext.InPreviewMode)
- {
- var text = value.ToString();
- var pos = text.IndexOf("