diff --git a/src/Umbraco.Core/Constants-Web.cs b/src/Umbraco.Core/Constants-Web.cs
index 8199d9fbd0..6d98a86580 100644
--- a/src/Umbraco.Core/Constants-Web.cs
+++ b/src/Umbraco.Core/Constants-Web.cs
@@ -7,8 +7,6 @@ namespace Umbraco.Core
///
public static class Web
{
- public const string UmbracoRouteDefinitionDataToken = "umbraco-route-def";
-
///
/// The preview cookie name
///
diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/ContentModelBinderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/ContentModelBinderTests.cs
index 01b6032c36..f4e3aed39f 100644
--- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/ContentModelBinderTests.cs
+++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/ContentModelBinderTests.cs
@@ -60,22 +60,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.ModelBinders
// Arrange
IPublishedContent pc = CreatePublishedContent();
ModelBindingContext bindingContext = CreateBindingContextForUmbracoRequest(typeof(ContentModel), pc);
- bindingContext.ActionContext.RouteData.Values.Remove(Constants.Web.UmbracoRouteDefinitionDataToken);
-
- // Act
- await _contentModelBinder.BindModelAsync(bindingContext);
-
- // Assert
- Assert.False(bindingContext.Result.IsModelSet);
- }
-
- [Test]
- public async Task Does_Not_Bind_Model_When_UmbracoToken_Has_Incorrect_Model()
- {
- // Arrange
- IPublishedContent pc = CreatePublishedContent();
- ModelBindingContext bindingContext = CreateBindingContextForUmbracoRequest(typeof(ContentModel), pc);
- bindingContext.ActionContext.RouteData.Values[Constants.Web.UmbracoRouteDefinitionDataToken] = new NonContentModel();
+ bindingContext.ActionContext.HttpContext.Features.Set(null);
// Act
await _contentModelBinder.BindModelAsync(bindingContext);
@@ -220,9 +205,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.ModelBinders
var httpContext = new DefaultHttpContext();
var routeData = new RouteData();
- routeData.Values.Add(Constants.Web.UmbracoRouteDefinitionDataToken, new UmbracoRouteValues(publishedRequest));
- {
- }
+ httpContext.Features.Set(new UmbracoRouteValues(publishedRequest));
var actionContext = new ActionContext(httpContext, routeData, new ActionDescriptor());
var metadataProvider = new EmptyModelMetadataProvider();
diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/SurfaceControllerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/SurfaceControllerTests.cs
index e286603f1c..53ae713564 100644
--- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/SurfaceControllerTests.cs
+++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/SurfaceControllerTests.cs
@@ -3,6 +3,7 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Moq;
@@ -126,15 +127,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers
var routeDefinition = new UmbracoRouteValues(publishedRequest);
- var routeData = new RouteData();
- routeData.Values.Add(CoreConstants.Web.UmbracoRouteDefinitionDataToken, routeDefinition);
+ var httpContext = new DefaultHttpContext();
+ httpContext.Features.Set(routeDefinition);
var ctrl = new TestSurfaceController(umbracoContextAccessor, Mock.Of(), Mock.Of())
{
ControllerContext = new ControllerContext()
{
- HttpContext = Mock.Of(),
- RouteData = routeData
+ HttpContext = httpContext,
+ RouteData = new RouteData()
}
};
diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/HijackedRouteEvaluatorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/ControllerActionSearcherTests.cs
similarity index 94%
rename from src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/HijackedRouteEvaluatorTests.cs
rename to src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/ControllerActionSearcherTests.cs
index 2d96476b30..9556640364 100644
--- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/HijackedRouteEvaluatorTests.cs
+++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/ControllerActionSearcherTests.cs
@@ -21,7 +21,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Routing
{
[TestFixture]
- public class HijackedRouteEvaluatorTests
+ public class ControllerActionSearcherTests
{
private class TestActionDescriptorCollectionProvider : ActionDescriptorCollectionProvider
{
@@ -88,11 +88,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Routing
[TestCase("Custom", "Render1", nameof(Render1Controller.Custom), true)]
public void Matches_Controller(string action, string controller, string resultAction, bool matches)
{
- var evaluator = new HijackedRouteEvaluator(
- new NullLogger(),
+ var query = new ControllerActionSearcher(
+ new NullLogger(),
GetActionDescriptors());
- HijackedRouteResult result = evaluator.Evaluate(controller, action);
+ ControllerActionSearchResult result = query.Find(controller, action);
Assert.AreEqual(matches, result.Success);
if (matches)
{
diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs
index a531c77fe1..e3147220bb 100644
--- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs
+++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs
@@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Routing;
@@ -49,7 +50,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Routing
TestHelper.GetHostingEnvironment(),
state,
routeValuesFactory ?? Mock.Of(),
- filter ?? Mock.Of(x => x.IsDocumentRequest(It.IsAny()) == true));
+ filter ?? Mock.Of(x => x.IsDocumentRequest(It.IsAny()) == true),
+ Mock.Of(),
+ Mock.Of());
return transformer;
}
@@ -74,7 +77,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Routing
typeof(TestController));
private IUmbracoRouteValuesFactory GetRouteValuesFactory(IPublishedRequest request)
- => Mock.Of(x => x.Create(It.IsAny(), It.IsAny(), It.IsAny()) == GetRouteValues(request));
+ => Mock.Of(x => x.Create(It.IsAny(), It.IsAny()) == GetRouteValues(request));
private IPublishedRouter GetRouter(IPublishedRequest request)
=> Mock.Of(x => x.RouteRequestAsync(It.IsAny(), It.IsAny()) == Task.FromResult(request));
@@ -140,6 +143,25 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Routing
Assert.AreEqual(request, umbracoContext.PublishedRequest);
}
+ [Test]
+ public async Task Assigns_UmbracoRouteValues_To_HttpContext_Feature()
+ {
+ IUmbracoContext umbracoContext = GetUmbracoContext(true);
+ IPublishedRequest request = Mock.Of();
+
+ UmbracoRouteValueTransformer transformer = GetTransformerWithRunState(
+ Mock.Of(x => x.UmbracoContext == umbracoContext),
+ router: GetRouter(request),
+ routeValuesFactory: GetRouteValuesFactory(request));
+
+ var httpContext = new DefaultHttpContext();
+ RouteValueDictionary result = await transformer.TransformAsync(httpContext, new RouteValueDictionary());
+
+ UmbracoRouteValues routeVals = httpContext.Features.Get();
+ Assert.IsNotNull(routeVals);
+ Assert.AreEqual(routeVals.PublishedRequest, umbracoContext.PublishedRequest);
+ }
+
[Test]
public async Task Assigns_Values_To_RouteValueDictionary()
{
diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValuesFactoryTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValuesFactoryTests.cs
index 17ce59862f..2c8dd3b395 100644
--- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValuesFactoryTests.cs
+++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValuesFactoryTests.cs
@@ -39,8 +39,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Routing
renderingDefaults,
Mock.Of(),
new UmbracoFeatures(),
- new HijackedRouteEvaluator(
- new NullLogger(),
+ new ControllerActionSearcher(
+ new NullLogger(),
Mock.Of()),
publishedRouter.Object);
@@ -56,7 +56,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Routing
UmbracoRouteValuesFactory factory = GetFactory(out Mock publishedRouter, out _);
- UmbracoRouteValues result = factory.Create(new DefaultHttpContext(), new RouteValueDictionary(), request);
+ UmbracoRouteValues result = factory.Create(new DefaultHttpContext(), request);
// The request has content, no template, no hijacked route and no disabled template features so UpdateRequestToNotFound will be called
publishedRouter.Verify(m => m.UpdateRequestToNotFound(It.IsAny()), Times.Once);
@@ -73,11 +73,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Routing
UmbracoRouteValuesFactory factory = GetFactory(out _, out UmbracoRenderingDefaults renderingDefaults);
var routeVals = new RouteValueDictionary();
- UmbracoRouteValues result = factory.Create(new DefaultHttpContext(), routeVals, request);
+ UmbracoRouteValues result = factory.Create(new DefaultHttpContext(), request);
Assert.IsNotNull(result);
- Assert.IsTrue(routeVals.ContainsKey(Constants.Web.UmbracoRouteDefinitionDataToken));
- Assert.AreEqual(result, routeVals[Constants.Web.UmbracoRouteDefinitionDataToken]);
Assert.AreEqual(renderingDefaults.DefaultControllerType, result.ControllerType);
Assert.AreEqual(UmbracoRouteValues.DefaultActionName, result.ActionName);
Assert.IsNull(result.TemplateName);
diff --git a/src/Umbraco.Web.Common/Controllers/PublishedRequestFilterAttribute.cs b/src/Umbraco.Web.Common/Controllers/PublishedRequestFilterAttribute.cs
index a33dba9ca6..a2c403bf7b 100644
--- a/src/Umbraco.Web.Common/Controllers/PublishedRequestFilterAttribute.cs
+++ b/src/Umbraco.Web.Common/Controllers/PublishedRequestFilterAttribute.cs
@@ -17,12 +17,13 @@ namespace Umbraco.Web.Common.Controllers
///
protected UmbracoRouteValues GetUmbracoRouteValues(ResultExecutingContext context)
{
- if (!context.RouteData.Values.TryGetValue(Core.Constants.Web.UmbracoRouteDefinitionDataToken, out var def))
+ UmbracoRouteValues routeVals = context.HttpContext.Features.Get();
+ if (routeVals == null)
{
- throw new InvalidOperationException($"No route value found with key {Core.Constants.Web.UmbracoRouteDefinitionDataToken}");
+ throw new InvalidOperationException($"No {nameof(UmbracoRouteValues)} feature was found in the HttpContext");
}
- return (UmbracoRouteValues)def;
+ return routeVals;
}
///
diff --git a/src/Umbraco.Web.Common/Controllers/RenderController.cs b/src/Umbraco.Web.Common/Controllers/RenderController.cs
index d9a2d05979..2359d6d13c 100644
--- a/src/Umbraco.Web.Common/Controllers/RenderController.cs
+++ b/src/Umbraco.Web.Common/Controllers/RenderController.cs
@@ -71,11 +71,11 @@ namespace Umbraco.Web.Common.Controllers
return _umbracoRouteValues;
}
- _umbracoRouteValues = HttpContext.GetRouteValue(Core.Constants.Web.UmbracoRouteDefinitionDataToken) as UmbracoRouteValues;
+ _umbracoRouteValues = HttpContext.Features.Get();
if (_umbracoRouteValues == null)
{
- throw new InvalidOperationException($"No route value found with key {Core.Constants.Web.UmbracoRouteDefinitionDataToken}");
+ throw new InvalidOperationException($"No {nameof(UmbracoRouteValues)} feature was found in the HttpContext");
}
return _umbracoRouteValues;
diff --git a/src/Umbraco.Web.Common/Localization/UmbracoPublishedContentCultureProvider.cs b/src/Umbraco.Web.Common/Localization/UmbracoPublishedContentCultureProvider.cs
index 7322ad2869..66177e965a 100644
--- a/src/Umbraco.Web.Common/Localization/UmbracoPublishedContentCultureProvider.cs
+++ b/src/Umbraco.Web.Common/Localization/UmbracoPublishedContentCultureProvider.cs
@@ -29,7 +29,8 @@ namespace Umbraco.Web.Common.Localization
///
public override Task DetermineProviderCultureResult(HttpContext httpContext)
{
- if (httpContext.GetRouteValue(Core.Constants.Web.UmbracoRouteDefinitionDataToken) is UmbracoRouteValues routeValues)
+ UmbracoRouteValues routeValues = httpContext.Features.Get();
+ if (routeValues != null)
{
string culture = routeValues.PublishedRequest?.Culture;
if (culture != null)
diff --git a/src/Umbraco.Web.Common/ModelBinders/ContentModelBinder.cs b/src/Umbraco.Web.Common/ModelBinders/ContentModelBinder.cs
index cc6678abfc..b93978693b 100644
--- a/src/Umbraco.Web.Common/ModelBinders/ContentModelBinder.cs
+++ b/src/Umbraco.Web.Common/ModelBinders/ContentModelBinder.cs
@@ -30,8 +30,8 @@ namespace Umbraco.Web.Common.ModelBinders
// only IPublishedContent will ever exist in the request so when this model binder is used as an IModelBinder
// in the aspnet pipeline it will really only support converting from IPublishedContent which is contained
// in the UmbracoRouteValues --> IContentModel
- if (!bindingContext.ActionContext.RouteData.Values.TryGetValue(Core.Constants.Web.UmbracoRouteDefinitionDataToken, out var source)
- || !(source is UmbracoRouteValues umbracoRouteValues))
+ UmbracoRouteValues umbracoRouteValues = bindingContext.HttpContext.Features.Get();
+ if (umbracoRouteValues == null)
{
return Task.CompletedTask;
}
diff --git a/src/Umbraco.Web.Common/Security/EncryptionHelper.cs b/src/Umbraco.Web.Common/Security/EncryptionHelper.cs
index 300afd530d..9dc1cd7497 100644
--- a/src/Umbraco.Web.Common/Security/EncryptionHelper.cs
+++ b/src/Umbraco.Web.Common/Security/EncryptionHelper.cs
@@ -1,5 +1,6 @@
-using System;
+using System;
using System.Collections.Generic;
+using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.Web;
@@ -12,64 +13,80 @@ namespace Umbraco.Web.Common.Security
{
public class EncryptionHelper
{
+ // TODO: Decide if these belong here... I don't think so since this all has to do with surface controller routes
+ // could also just be injected too....
+
private static IDataProtector CreateDataProtector(IDataProtectionProvider dataProtectionProvider)
- {
- return dataProtectionProvider.CreateProtector(nameof(EncryptionHelper));
- }
+ => dataProtectionProvider.CreateProtector(nameof(EncryptionHelper));
public static string Decrypt(string encryptedString, IDataProtectionProvider dataProtectionProvider)
- {
- return CreateDataProtector(dataProtectionProvider).Unprotect(encryptedString);
- }
+ => CreateDataProtector(dataProtectionProvider).Unprotect(encryptedString);
public static string Encrypt(string plainString, IDataProtectionProvider dataProtectionProvider)
- {
- return CreateDataProtector(dataProtectionProvider).Protect(plainString);
- }
+ => 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));
+ if (dataProtectionProvider is null)
+ {
+ throw new ArgumentNullException(nameof(dataProtectionProvider));
+ }
- //need to create a params string as Base64 to put into our hidden field to use during the routes
+ if (string.IsNullOrEmpty(controllerName))
+ {
+ throw new ArgumentException($"'{nameof(controllerName)}' cannot be null or empty.", nameof(controllerName));
+ }
+
+ if (string.IsNullOrEmpty(controllerAction))
+ {
+ throw new ArgumentException($"'{nameof(controllerAction)}' cannot be null or empty.", nameof(controllerAction));
+ }
+
+ if (area is 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
+ // 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
protected UmbracoPageResult CurrentUmbracoPage()
=> new UmbracoPageResult(ProfilingLogger);
-
- ///
- /// we need to recursively find the route definition based on the parent view context
- ///
- private Attempt TryGetRouteDefinitionFromAncestorViewContexts()
- {
- var currentContext = ControllerContext;
- while (!(currentContext is null))
- {
- var currentRouteData = currentContext.RouteData;
- if (currentRouteData.Values.ContainsKey(Constants.Web.UmbracoRouteDefinitionDataToken))
- {
- return Attempt.Succeed((UmbracoRouteValues)currentRouteData.Values[Constants.Web.UmbracoRouteDefinitionDataToken]);
- }
- }
-
- return Attempt.Fail(
- new InvalidOperationException("Cannot find the Umbraco route definition in the route values, the request must be made in the context of an Umbraco request"));
- }
}
}
diff --git a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs
index 42174ecb73..b1d21e87b9 100644
--- a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs
+++ b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs
@@ -37,7 +37,7 @@ namespace Umbraco.Web.Website.DependencyInjection
builder.Services.AddDataProtection();
builder.Services.AddScoped();
- builder.Services.AddSingleton();
+ builder.Services.AddSingleton();
builder.Services.AddSingleton();
builder.Services.AddSingleton();
builder.Services.AddSingleton();
diff --git a/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs b/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs
index f79648b19a..ac6154f645 100644
--- a/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs
+++ b/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs
@@ -243,15 +243,12 @@ namespace Umbraco.Extensions
return htmlHelper.ActionLink(actionName, metaData.ControllerName, routeVals);
}
- #region BeginUmbracoForm
-
///
/// Used for rendering out the Form for BeginUmbracoForm
///
internal class UmbracoForm : MvcForm
{
private readonly ViewContext _viewContext;
- private bool _disposed;
private readonly string _encryptedString;
private readonly string _controllerName;
@@ -272,15 +269,8 @@ namespace Umbraco.Extensions
_encryptedString = EncryptionHelper.CreateEncryptedRouteString(GetRequiredService(viewContext), controllerName, controllerAction, area, additionalRouteVals);
}
- protected new void Dispose()
+ protected override void GenerateEndForm()
{
- if (_disposed)
- {
- return;
- }
-
- _disposed = true;
-
// Detect if the call is targeting UmbRegisterController/UmbProfileController/UmbLoginStatusController/UmbLoginController and if it is we automatically output a AntiForgeryToken()
// We have a controllerName and area so we can match
if (_controllerName == "UmbRegister"
@@ -295,7 +285,7 @@ namespace Umbraco.Extensions
// write out the hidden surface form routes
_viewContext.Writer.Write("");
- base.Dispose();
+ base.GenerateEndForm();
}
}
@@ -710,7 +700,6 @@ namespace Umbraco.Extensions
return theForm;
}
- #endregion
#region If
diff --git a/src/Umbraco.Web.Website/Routing/HijackedRouteResult.cs b/src/Umbraco.Web.Website/Routing/ControllerActionSearchResult.cs
similarity index 53%
rename from src/Umbraco.Web.Website/Routing/HijackedRouteResult.cs
rename to src/Umbraco.Web.Website/Routing/ControllerActionSearchResult.cs
index f88bdfa2fd..2c2f4802df 100644
--- a/src/Umbraco.Web.Website/Routing/HijackedRouteResult.cs
+++ b/src/Umbraco.Web.Website/Routing/ControllerActionSearchResult.cs
@@ -1,21 +1,16 @@
-using System;
+using System;
namespace Umbraco.Web.Website.Routing
{
///
- /// The result from evaluating if a route can be hijacked
+ /// The result from querying a controller/action in the existing routes
///
- public class HijackedRouteResult
+ public class ControllerActionSearchResult
{
///
- /// Returns a failed result
+ /// Initializes a new instance of the class.
///
- public static HijackedRouteResult Failed() => new HijackedRouteResult(false, null, null, null);
-
- ///
- /// Initializes a new instance of the class.
- ///
- public HijackedRouteResult(
+ private ControllerActionSearchResult(
bool success,
string controllerName,
Type controllerType,
@@ -28,7 +23,18 @@ namespace Umbraco.Web.Website.Routing
}
///
- /// Gets a value indicating if the route could be hijacked
+ /// Initializes a new instance of the class.
+ ///
+ public ControllerActionSearchResult(
+ string controllerName,
+ Type controllerType,
+ string actionName)
+ : this(true, controllerName, controllerType, actionName)
+ {
+ }
+
+ ///
+ /// Gets a value indicating whether the route could be hijacked
///
public bool Success { get; }
@@ -46,5 +52,10 @@ namespace Umbraco.Web.Website.Routing
/// Gets the Acton name
///
public string ActionName { get; }
+
+ ///
+ /// Returns a failed result
+ ///
+ public static ControllerActionSearchResult Failed() => new ControllerActionSearchResult(false, null, null, null);
}
}
diff --git a/src/Umbraco.Web.Website/Routing/HijackedRouteEvaluator.cs b/src/Umbraco.Web.Website/Routing/ControllerActionSearcher.cs
similarity index 81%
rename from src/Umbraco.Web.Website/Routing/HijackedRouteEvaluator.cs
rename to src/Umbraco.Web.Website/Routing/ControllerActionSearcher.cs
index 79036a01e1..f38c4676c8 100644
--- a/src/Umbraco.Web.Website/Routing/HijackedRouteEvaluator.cs
+++ b/src/Umbraco.Web.Website/Routing/ControllerActionSearcher.cs
@@ -11,19 +11,19 @@ using Umbraco.Web.Common.Controllers;
namespace Umbraco.Web.Website.Routing
{
///
- /// Determines if a custom controller can hijack the current route
+ /// Used to find a controller/action in the current available routes
///
- public class HijackedRouteEvaluator
+ public class ControllerActionSearcher : IControllerActionSearcher
{
- private readonly ILogger _logger;
+ private readonly ILogger _logger;
private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider;
private const string DefaultActionName = nameof(RenderController.Index);
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
- public HijackedRouteEvaluator(
- ILogger logger,
+ public ControllerActionSearcher(
+ ILogger logger,
IActionDescriptorCollectionProvider actionDescriptorCollectionProvider)
{
_logger = logger;
@@ -33,7 +33,8 @@ namespace Umbraco.Web.Website.Routing
///
/// Determines if a custom controller can hijack the current route
///
- public HijackedRouteResult Evaluate(string controller, string action)
+ /// The controller type to find
+ public ControllerActionSearchResult Find(string controller, string action)
{
IReadOnlyList candidates = FindControllerCandidates(controller, action, DefaultActionName);
@@ -45,8 +46,8 @@ namespace Umbraco.Web.Website.Routing
{
ControllerActionDescriptor controllerDescriptor = customControllerCandidates[0];
- // ensure the controller is of type IRenderController and ControllerBase
- if (TypeHelper.IsTypeAssignableFrom(controllerDescriptor.ControllerTypeInfo)
+ // ensure the controller is of type T and ControllerBase
+ if (TypeHelper.IsTypeAssignableFrom(controllerDescriptor.ControllerTypeInfo)
&& TypeHelper.IsTypeAssignableFrom(controllerDescriptor.ControllerTypeInfo))
{
// now check if the custom action matches
@@ -61,8 +62,7 @@ namespace Umbraco.Web.Website.Routing
}
// it's a hijacked route with a custom controller, so return the the values
- return new HijackedRouteResult(
- true,
+ return new ControllerActionSearchResult(
controllerDescriptor.ControllerName,
controllerDescriptor.ControllerTypeInfo,
resultingAction);
@@ -73,7 +73,7 @@ namespace Umbraco.Web.Website.Routing
"The current Document Type {ContentTypeAlias} matches a locally declared controller of type {ControllerName}. Custom Controllers for Umbraco routing must implement '{UmbracoRenderController}' and inherit from '{UmbracoControllerBase}'.",
controller,
controllerDescriptor.ControllerTypeInfo.FullName,
- typeof(IRenderController).FullName,
+ typeof(T).FullName,
typeof(ControllerBase).FullName);
// we cannot route to this custom controller since it is not of the correct type so we'll continue with the defaults
@@ -81,7 +81,7 @@ namespace Umbraco.Web.Website.Routing
}
}
- return HijackedRouteResult.Failed();
+ return ControllerActionSearchResult.Failed();
}
///
diff --git a/src/Umbraco.Web.Website/Routing/IControllerActionSearcher.cs b/src/Umbraco.Web.Website/Routing/IControllerActionSearcher.cs
new file mode 100644
index 0000000000..36b4382cc2
--- /dev/null
+++ b/src/Umbraco.Web.Website/Routing/IControllerActionSearcher.cs
@@ -0,0 +1,7 @@
+namespace Umbraco.Web.Website.Routing
+{
+ public interface IControllerActionSearcher
+ {
+ ControllerActionSearchResult Find(string controller, string action);
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Web.Website/Routing/IUmbracoRouteValuesFactory.cs b/src/Umbraco.Web.Website/Routing/IUmbracoRouteValuesFactory.cs
index 7af41d865b..f584627e31 100644
--- a/src/Umbraco.Web.Website/Routing/IUmbracoRouteValuesFactory.cs
+++ b/src/Umbraco.Web.Website/Routing/IUmbracoRouteValuesFactory.cs
@@ -13,6 +13,6 @@ namespace Umbraco.Web.Website.Routing
///
/// Creates
///
- UmbracoRouteValues Create(HttpContext httpContext, RouteValueDictionary values, IPublishedRequest request);
+ UmbracoRouteValues Create(HttpContext httpContext, IPublishedRequest request);
}
}
diff --git a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs
index af23105099..a4ab61b3cc 100644
--- a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs
+++ b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs
@@ -1,14 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
+using Microsoft.Extensions.Primitives;
using Umbraco.Core;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Hosting;
using Umbraco.Extensions;
using Umbraco.Web.Common.Routing;
+using Umbraco.Web.Common.Security;
using Umbraco.Web.Routing;
using Umbraco.Web.Website.Controllers;
using RouteDirection = Umbraco.Web.Routing.RouteDirection;
@@ -35,6 +43,10 @@ namespace Umbraco.Web.Website.Routing
private readonly IRuntimeState _runtime;
private readonly IUmbracoRouteValuesFactory _routeValuesFactory;
private readonly IRoutableDocumentFilter _routableDocumentFilter;
+ private readonly IDataProtectionProvider _dataProtectionProvider;
+ private readonly IControllerActionSearcher _controllerActionSearcher;
+ private const string ControllerToken = "controller";
+ private const string ActionToken = "action";
///
/// Initializes a new instance of the class.
@@ -47,21 +59,25 @@ namespace Umbraco.Web.Website.Routing
IHostingEnvironment hostingEnvironment,
IRuntimeState runtime,
IUmbracoRouteValuesFactory routeValuesFactory,
- IRoutableDocumentFilter routableDocumentFilter)
+ IRoutableDocumentFilter routableDocumentFilter,
+ IDataProtectionProvider dataProtectionProvider,
+ IControllerActionSearcher controllerActionSearcher)
{
if (globalSettings is null)
{
- throw new System.ArgumentNullException(nameof(globalSettings));
+ throw new ArgumentNullException(nameof(globalSettings));
}
- _logger = logger ?? throw new System.ArgumentNullException(nameof(logger));
- _umbracoContextAccessor = umbracoContextAccessor ?? throw new System.ArgumentNullException(nameof(umbracoContextAccessor));
- _publishedRouter = publishedRouter ?? throw new System.ArgumentNullException(nameof(publishedRouter));
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor));
+ _publishedRouter = publishedRouter ?? throw new ArgumentNullException(nameof(publishedRouter));
_globalSettings = globalSettings.Value;
- _hostingEnvironment = hostingEnvironment ?? throw new System.ArgumentNullException(nameof(hostingEnvironment));
- _runtime = runtime ?? throw new System.ArgumentNullException(nameof(runtime));
- _routeValuesFactory = routeValuesFactory ?? throw new System.ArgumentNullException(nameof(routeValuesFactory));
- _routableDocumentFilter = routableDocumentFilter ?? throw new System.ArgumentNullException(nameof(routableDocumentFilter));
+ _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));
+ _runtime = runtime ?? throw new ArgumentNullException(nameof(runtime));
+ _routeValuesFactory = routeValuesFactory ?? throw new ArgumentNullException(nameof(routeValuesFactory));
+ _routableDocumentFilter = routableDocumentFilter ?? throw new ArgumentNullException(nameof(routableDocumentFilter));
+ _dataProtectionProvider = dataProtectionProvider;
+ _controllerActionSearcher = controllerActionSearcher;
}
///
@@ -87,23 +103,33 @@ namespace Umbraco.Web.Website.Routing
// Check if there is no existing content and return the no content controller
if (!_umbracoContextAccessor.UmbracoContext.Content.HasContent())
{
- values["controller"] = ControllerExtensions.GetControllerName();
- values["action"] = nameof(RenderNoContentController.Index);
+ values[ControllerToken] = ControllerExtensions.GetControllerName();
+ values[ActionToken] = nameof(RenderNoContentController.Index);
- return await Task.FromResult(values);
+ return values;
}
IPublishedRequest publishedRequest = await RouteRequestAsync(_umbracoContextAccessor.UmbracoContext);
- UmbracoRouteValues routeDef = _routeValuesFactory.Create(httpContext, values, publishedRequest);
+ UmbracoRouteValues umbracoRouteValues = _routeValuesFactory.Create(httpContext, publishedRequest);
- values["controller"] = routeDef.ControllerName;
- if (string.IsNullOrWhiteSpace(routeDef.ActionName) == false)
+ // Store the route values as a httpcontext feature
+ httpContext.Features.Set(umbracoRouteValues);
+
+ // Need to check if there is form data being posted back to an Umbraco URL
+ PostedDataProxyInfo postedInfo = GetFormInfo(httpContext, values);
+ if (postedInfo != null)
{
- values["action"] = routeDef.ActionName;
+ return HandlePostedValues(postedInfo, httpContext, values);
}
- return await Task.FromResult(values);
+ values[ControllerToken] = umbracoRouteValues.ControllerName;
+ if (string.IsNullOrWhiteSpace(umbracoRouteValues.ActionName) == false)
+ {
+ values[ActionToken] = umbracoRouteValues.ActionName;
+ }
+
+ return values;
}
private async Task RouteRequestAsync(IUmbracoContext umbracoContext)
@@ -123,5 +149,92 @@ namespace Umbraco.Web.Website.Routing
return routedRequest;
}
+
+ ///
+ /// Checks the request and query strings to see if it matches the definition of having a Surface controller
+ /// posted/get value, if so, then we return a PostedDataProxyInfo object with the correct information.
+ ///
+ private PostedDataProxyInfo GetFormInfo(HttpContext httpContext, RouteValueDictionary values)
+ {
+ if (httpContext is null)
+ {
+ throw new ArgumentNullException(nameof(httpContext));
+ }
+
+ // if it is a POST/GET then a value must be in the request
+ if (!httpContext.Request.Query.TryGetValue("ufprt", out StringValues encodedVal)
+ && (!httpContext.Request.HasFormContentType || !httpContext.Request.Form.TryGetValue("ufprt", out encodedVal)))
+ {
+ return null;
+ }
+
+ if (!EncryptionHelper.DecryptAndValidateEncryptedRouteString(
+ _dataProtectionProvider,
+ encodedVal,
+ out IDictionary decodedParts))
+ {
+ return null;
+ }
+
+ // Get all route values that are not the default ones and add them separately so they eventually get to action parameters
+ foreach (KeyValuePair item in decodedParts.Where(x => ReservedAdditionalKeys.AllKeys.Contains(x.Key) == false))
+ {
+ values[item.Key] = item.Value;
+ }
+
+ // return the proxy info without the surface id... could be a local controller.
+ return new PostedDataProxyInfo
+ {
+ ControllerName = WebUtility.UrlDecode(decodedParts.First(x => x.Key == ReservedAdditionalKeys.Controller).Value),
+ ActionName = WebUtility.UrlDecode(decodedParts.First(x => x.Key == ReservedAdditionalKeys.Action).Value),
+ Area = WebUtility.UrlDecode(decodedParts.First(x => x.Key == ReservedAdditionalKeys.Area).Value),
+ };
+ }
+
+ private RouteValueDictionary HandlePostedValues(PostedDataProxyInfo postedInfo, HttpContext httpContext, RouteValueDictionary values)
+ {
+ // set the standard route values/tokens
+ values[ControllerToken] = postedInfo.ControllerName;
+ values[ActionToken] = postedInfo.ActionName;
+
+ ControllerActionSearchResult surfaceControllerQueryResult = _controllerActionSearcher.Find(postedInfo.ControllerName, postedInfo.ActionName);
+
+ if (surfaceControllerQueryResult == null || !surfaceControllerQueryResult.Success)
+ {
+ throw new InvalidOperationException("Could not find a Surface controller route in the RouteTable for controller name " + postedInfo.ControllerName);
+ }
+
+ // set the area if one is there.
+ if (!postedInfo.Area.IsNullOrWhiteSpace())
+ {
+ values["area"] = postedInfo.Area;
+ }
+
+ return values;
+ }
+
+ private class PostedDataProxyInfo
+ {
+ public string ControllerName { get; set; }
+
+ public string ActionName { get; set; }
+
+ public string Area { get; set; }
+ }
+
+ // Define reserved dictionary keys for controller, action and area specified in route additional values data
+ private static class ReservedAdditionalKeys
+ {
+ internal static readonly string[] AllKeys = new[]
+ {
+ Controller,
+ Action,
+ Area
+ };
+
+ internal const string Controller = "c";
+ internal const string Action = "a";
+ internal const string Area = "ar";
+ }
}
}
diff --git a/src/Umbraco.Web.Website/Routing/UmbracoRouteValuesFactory.cs b/src/Umbraco.Web.Website/Routing/UmbracoRouteValuesFactory.cs
index d26216204e..9d75733f1f 100644
--- a/src/Umbraco.Web.Website/Routing/UmbracoRouteValuesFactory.cs
+++ b/src/Umbraco.Web.Website/Routing/UmbracoRouteValuesFactory.cs
@@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Routing;
using Umbraco.Core;
using Umbraco.Core.Strings;
using Umbraco.Extensions;
+using Umbraco.Web.Common.Controllers;
using Umbraco.Web.Common.Routing;
using Umbraco.Web.Features;
using Umbraco.Web.Routing;
@@ -20,7 +21,7 @@ namespace Umbraco.Web.Website.Routing
private readonly IUmbracoRenderingDefaults _renderingDefaults;
private readonly IShortStringHelper _shortStringHelper;
private readonly UmbracoFeatures _umbracoFeatures;
- private readonly HijackedRouteEvaluator _hijackedRouteEvaluator;
+ private readonly IControllerActionSearcher _controllerActionSearcher;
private readonly IPublishedRouter _publishedRouter;
private readonly Lazy _defaultControllerName;
@@ -31,13 +32,13 @@ namespace Umbraco.Web.Website.Routing
IUmbracoRenderingDefaults renderingDefaults,
IShortStringHelper shortStringHelper,
UmbracoFeatures umbracoFeatures,
- HijackedRouteEvaluator hijackedRouteEvaluator,
+ IControllerActionSearcher controllerActionSearcher,
IPublishedRouter publishedRouter)
{
_renderingDefaults = renderingDefaults;
_shortStringHelper = shortStringHelper;
_umbracoFeatures = umbracoFeatures;
- _hijackedRouteEvaluator = hijackedRouteEvaluator;
+ _controllerActionSearcher = controllerActionSearcher;
_publishedRouter = publishedRouter;
_defaultControllerName = new Lazy(() => ControllerExtensions.GetControllerName(_renderingDefaults.DefaultControllerType));
}
@@ -48,18 +49,13 @@ namespace Umbraco.Web.Website.Routing
protected string DefaultControllerName => _defaultControllerName.Value;
///
- public UmbracoRouteValues Create(HttpContext httpContext, RouteValueDictionary values, IPublishedRequest request)
+ public UmbracoRouteValues Create(HttpContext httpContext, IPublishedRequest request)
{
if (httpContext is null)
{
throw new ArgumentNullException(nameof(httpContext));
}
- if (values is null)
- {
- throw new ArgumentNullException(nameof(values));
- }
-
if (request is null)
{
throw new ArgumentNullException(nameof(request));
@@ -90,9 +86,6 @@ namespace Umbraco.Web.Website.Routing
def = CheckNoTemplate(def);
- // store the route definition
- values.TryAdd(Constants.Web.UmbracoRouteDefinitionDataToken, def);
-
return def;
}
@@ -106,7 +99,7 @@ namespace Umbraco.Web.Website.Routing
var customControllerName = request.PublishedContent?.ContentType?.Alias;
if (customControllerName != null)
{
- HijackedRouteResult hijackedResult = _hijackedRouteEvaluator.Evaluate(customControllerName, def.TemplateName);
+ ControllerActionSearchResult hijackedResult = _controllerActionSearcher.Find(customControllerName, def.TemplateName);
if (hijackedResult.Success)
{
return new UmbracoRouteValues(
diff --git a/src/Umbraco.Web/Mvc/RedirectToUmbracoPageResult.cs b/src/Umbraco.Web/Mvc/RedirectToUmbracoPageResult.cs
deleted file mode 100644
index 4658910ab0..0000000000
--- a/src/Umbraco.Web/Mvc/RedirectToUmbracoPageResult.cs
+++ /dev/null
@@ -1,278 +0,0 @@
-using System;
-using System.Collections.Specialized;
-using System.Linq;
-using System.Web;
-using System.Web.Mvc;
-using Umbraco.Core;
-using Umbraco.Core.Models;
-using Umbraco.Core.Models.PublishedContent;
-using Umbraco.Web.Composing;
-using Umbraco.Web.Routing;
-
-namespace Umbraco.Web.Mvc
-{
- ///
- /// Redirects to an Umbraco page by Id or Entity
- ///
- /// Migrated already to .Net Core
- public class RedirectToUmbracoPageResult : ActionResult
- {
- private IPublishedContent _publishedContent;
- private readonly int _pageId;
- private readonly Guid _key;
- private NameValueCollection _queryStringValues;
- private IPublishedUrlProvider _publishedUrlProvider;
- private string _url;
-
- public string Url
- {
- get
- {
- if (!_url.IsNullOrWhiteSpace()) return _url;
-
- if (PublishedContent == null)
- {
- throw new InvalidOperationException(string.Format("Cannot redirect, no entity was found for id {0}", _pageId));
- }
-
- var result = _publishedUrlProvider.GetUrl(PublishedContent.Id);
- if (result != "#")
- {
- _url = result;
- return _url;
- }
-
- throw new InvalidOperationException(string.Format("Could not route to entity with id {0}, the NiceUrlProvider could not generate a URL", _pageId));
-
- }
- }
-
- public int PageId
- {
- get { return _pageId; }
- }
-
- public Guid Key
- {
- get { return _key; }
- }
- public IPublishedContent PublishedContent
- {
- get
- {
- if (_publishedContent != null) return _publishedContent;
-
- if (_pageId != default(int))
- {
- _publishedContent = Current.UmbracoContext.Content.GetById(_pageId);
- }
-
- else if (_key != default(Guid))
- {
- _publishedContent = Current.UmbracoContext.Content.GetById(_key);
- }
-
- return _publishedContent;
- }
- }
-
- ///
- /// Creates a new RedirectToUmbracoResult
- ///
- ///
- public RedirectToUmbracoPageResult(int pageId)
- : this(pageId, Current.PublishedUrlProvider)
- {
- }
-
- ///
- /// Creates a new RedirectToUmbracoResult
- ///
- ///
- ///
- public RedirectToUmbracoPageResult(int pageId, NameValueCollection queryStringValues)
- : this(pageId, queryStringValues, Current.PublishedUrlProvider)
- {
- }
-
- ///
- /// Creates a new RedirectToUmbracoResult
- ///
- ///
- ///
- public RedirectToUmbracoPageResult(int pageId, string queryString)
- : this(pageId, queryString, Current.PublishedUrlProvider)
- {
- }
-
- ///
- /// Creates a new RedirectToUmbracoResult
- ///
- ///
- public RedirectToUmbracoPageResult(IPublishedContent publishedContent)
- : this(publishedContent, Current.PublishedUrlProvider)
- {
- }
-
- ///
- /// Creates a new RedirectToUmbracoResult
- ///
- ///
- ///
- public RedirectToUmbracoPageResult(IPublishedContent publishedContent, NameValueCollection queryStringValues)
- : this(publishedContent, queryStringValues, Current.PublishedUrlProvider)
- {
- }
-
- ///
- /// Creates a new RedirectToUmbracoResult
- ///
- ///
- ///
- public RedirectToUmbracoPageResult(IPublishedContent publishedContent, string queryString)
- : this(publishedContent, queryString, Current.PublishedUrlProvider)
- {
- }
-
- ///
- /// Creates a new RedirectToUmbracoResult
- ///
- ///
- ///
- public RedirectToUmbracoPageResult(int pageId, IPublishedUrlProvider publishedUrlProvider)
- {
- _pageId = pageId;
- _publishedUrlProvider = publishedUrlProvider;
- }
-
- ///
- /// Creates a new RedirectToUmbracoResult
- ///
- ///
- ///
- ///
- public RedirectToUmbracoPageResult(int pageId, NameValueCollection queryStringValues, IPublishedUrlProvider publishedUrlProvider)
- {
- _pageId = pageId;
- _queryStringValues = queryStringValues;
- _publishedUrlProvider = publishedUrlProvider;
- }
-
- ///
- /// Creates a new RedirectToUmbracoResult
- ///
- ///
- ///
- ///
- public RedirectToUmbracoPageResult(int pageId, string queryString, IPublishedUrlProvider publishedUrlProvider)
- {
- _pageId = pageId;
- _queryStringValues = ParseQueryString(queryString);
- _publishedUrlProvider = publishedUrlProvider;
- }
-
- ///
- /// Creates a new RedirectToUmbracoResult
- ///
- ///
- ///
- public RedirectToUmbracoPageResult(Guid key)
- {
- _key = key;
- }
-
- ///
- /// Creates a new RedirectToUmbracoResult
- ///
- ///
- ///
- public RedirectToUmbracoPageResult(Guid key, NameValueCollection queryStringValues)
- {
- _key = key;
- _queryStringValues = queryStringValues;
- }
-
- ///
- /// Creates a new RedirectToUmbracoResult
- ///
- ///
- ///
- public RedirectToUmbracoPageResult(Guid key, string queryString)
- {
- _key = key;
- _queryStringValues = ParseQueryString(queryString);
- }
-
- ///
- /// Creates a new RedirectToUmbracoResult
- ///
- ///
- ///
- public RedirectToUmbracoPageResult(IPublishedContent publishedContent, IPublishedUrlProvider publishedUrlProvider)
- {
- _publishedContent = publishedContent;
- _pageId = publishedContent.Id;
- _publishedUrlProvider = publishedUrlProvider;
- }
-
- ///
- /// Creates a new RedirectToUmbracoResult
- ///
- ///
- ///
- ///
- public RedirectToUmbracoPageResult(IPublishedContent publishedContent, NameValueCollection queryStringValues, IPublishedUrlProvider publishedUrlProvider)
- {
- _publishedContent = publishedContent;
- _pageId = publishedContent.Id;
- _queryStringValues = queryStringValues;
- _publishedUrlProvider = publishedUrlProvider;
- }
-
- ///
- /// Creates a new RedirectToUmbracoResult
- ///
- ///
- ///
- ///
- public RedirectToUmbracoPageResult(IPublishedContent publishedContent, string queryString, IPublishedUrlProvider publishedUrlProvider)
- {
- _publishedContent = publishedContent;
- _pageId = publishedContent.Id;
- _queryStringValues = ParseQueryString(queryString);
- _publishedUrlProvider = publishedUrlProvider;
- }
-
- public override void ExecuteResult(ControllerContext context)
- {
- if (context == null) throw new ArgumentNullException("context");
-
- if (context.IsChildAction)
- {
- throw new InvalidOperationException("Cannot redirect from a Child Action");
- }
-
- var destinationUrl = UrlHelper.GenerateContentUrl(Url, context.HttpContext);
-
- if (_queryStringValues != null && _queryStringValues.Count > 0)
- {
- destinationUrl = destinationUrl += "?" + string.Join("&",
- _queryStringValues.AllKeys.Select(x => x + "=" + HttpUtility.UrlEncode(_queryStringValues[x])));
- }
-
- context.Controller.TempData.Keep();
-
- context.HttpContext.Response.Redirect(destinationUrl, endResponse: false);
- }
-
- private NameValueCollection ParseQueryString(string queryString)
- {
- if (!string.IsNullOrEmpty(queryString))
- {
- return HttpUtility.ParseQueryString(queryString);
- }
-
- return null;
- }
- }
-}
diff --git a/src/Umbraco.Web/Mvc/RedirectToUmbracoUrlResult.cs b/src/Umbraco.Web/Mvc/RedirectToUmbracoUrlResult.cs
deleted file mode 100644
index 6f97bff534..0000000000
--- a/src/Umbraco.Web/Mvc/RedirectToUmbracoUrlResult.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using System;
-using System.Web.Mvc;
-
-namespace Umbraco.Web.Mvc
-{
- ///
- /// Redirects to the current URL rendering an Umbraco page including it's query strings
- ///
- ///
- /// This is useful if you need to redirect
- /// to the current page but the current page is actually a rewritten URL normally done with something like
- /// Server.Transfer. It is also handy if you want to persist the query strings.
- ///
- /// Migrated already to .Net Core
- public class RedirectToUmbracoUrlResult : ActionResult
- {
- private readonly IUmbracoContext _umbracoContext;
-
- ///
- /// Creates a new RedirectToUmbracoResult
- ///
- ///
- public RedirectToUmbracoUrlResult(IUmbracoContext umbracoContext)
- {
- _umbracoContext = umbracoContext;
- }
-
- public override void ExecuteResult(ControllerContext context)
- {
- if (context == null) throw new ArgumentNullException("context");
-
- if (context.IsChildAction)
- {
- throw new InvalidOperationException("Cannot redirect from a Child Action");
- }
-
- var destinationUrl = _umbracoContext.OriginalRequestUrl.PathAndQuery;
- context.Controller.TempData.Keep();
-
- context.HttpContext.Response.Redirect(destinationUrl, endResponse: false);
- }
- }
-}
diff --git a/src/Umbraco.Web/Mvc/RenderRouteHandler.cs b/src/Umbraco.Web/Mvc/RenderRouteHandler.cs
index c88958d2fe..f5b536d259 100644
--- a/src/Umbraco.Web/Mvc/RenderRouteHandler.cs
+++ b/src/Umbraco.Web/Mvc/RenderRouteHandler.cs
@@ -3,16 +3,12 @@ using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
-using System.Web.SessionState;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Logging;
using Umbraco.Core;
-using Umbraco.Core.Composing;
using Umbraco.Core.Strings;
using Umbraco.Web.Features;
using Umbraco.Web.Models;
using Umbraco.Web.Routing;
-using Umbraco.Core.Strings;
using Current = Umbraco.Web.Composing.Current;
namespace Umbraco.Web.Mvc
@@ -27,29 +23,21 @@ namespace Umbraco.Web.Mvc
internal const string Area = "ar";
}
- private readonly IControllerFactory _controllerFactory;
- private readonly IShortStringHelper _shortStringHelper;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IUmbracoContext _umbracoContext;
public RenderRouteHandler(IUmbracoContextAccessor umbracoContextAccessor, IControllerFactory controllerFactory, IShortStringHelper shortStringHelper)
{
_umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor));
- _controllerFactory = controllerFactory ?? throw new ArgumentNullException(nameof(controllerFactory));
- _shortStringHelper = shortStringHelper ?? throw new ArgumentNullException(nameof(shortStringHelper));
}
public RenderRouteHandler(IUmbracoContext umbracoContext, IControllerFactory controllerFactory, IShortStringHelper shortStringHelper)
{
_umbracoContext = umbracoContext ?? throw new ArgumentNullException(nameof(umbracoContext));
- _controllerFactory = controllerFactory ?? throw new ArgumentNullException(nameof(controllerFactory));
- _shortStringHelper = shortStringHelper ?? throw new ArgumentNullException(nameof(shortStringHelper));
}
private IUmbracoContext UmbracoContext => _umbracoContext ?? _umbracoContextAccessor.UmbracoContext;
- private UmbracoFeatures Features => Current.Factory.GetRequiredService(); // TODO: inject
-
#region IRouteHandler Members
///
@@ -74,26 +62,15 @@ namespace Umbraco.Web.Mvc
#endregion
- private void UpdateRouteDataForRequest(ContentModel contentModel, RequestContext requestContext)
- {
- if (contentModel == null) throw new ArgumentNullException(nameof(contentModel));
- if (requestContext == null) throw new ArgumentNullException(nameof(requestContext));
-
- // requestContext.RouteData.DataTokens[Core.Constants.Web.UmbracoDataToken] = contentModel;
- // the rest should not change -- it's only the published content that has changed
- }
-
///
/// Checks the request and query strings to see if it matches the definition of having a Surface controller
/// posted/get value, if so, then we return a PostedDataProxyInfo object with the correct information.
///
- ///
- ///
internal static PostedDataProxyInfo GetFormInfo(RequestContext requestContext)
{
if (requestContext == null) throw new ArgumentNullException(nameof(requestContext));
- //if it is a POST/GET then a value must be in the request
+ // if it is a POST/GET then a value must be in the request
if (requestContext.HttpContext.Request.QueryString["ufprt"].IsNullOrWhiteSpace()
&& requestContext.HttpContext.Request.Form["ufprt"].IsNullOrWhiteSpace())
{
@@ -105,12 +82,12 @@ namespace Umbraco.Web.Mvc
switch (requestContext.HttpContext.Request.RequestType)
{
case "POST":
- //get the value from the request.
- //this field will contain an encrypted version of the surface route vals.
+ // get the value from the request.
+ // this field will contain an encrypted version of the surface route vals.
encodedVal = requestContext.HttpContext.Request.Form["ufprt"];
break;
case "GET":
- //this field will contain an encrypted version of the surface route vals.
+ // this field will contain an encrypted version of the surface route vals.
encodedVal = requestContext.HttpContext.Request.QueryString["ufprt"];
break;
default:
@@ -144,8 +121,6 @@ namespace Umbraco.Web.Mvc
/// Handles a posted form to an Umbraco URL and ensures the correct controller is routed to and that
/// the right DataTokens are set.
///
- ///
- ///
internal static IHttpHandler HandlePostedValues(RequestContext requestContext, PostedDataProxyInfo postedInfo)
{
if (requestContext == null) throw new ArgumentNullException(nameof(requestContext));
diff --git a/src/Umbraco.Web/Mvc/SurfaceController.cs b/src/Umbraco.Web/Mvc/SurfaceController.cs
index fa67248e7d..483461ae57 100644
--- a/src/Umbraco.Web/Mvc/SurfaceController.cs
+++ b/src/Umbraco.Web/Mvc/SurfaceController.cs
@@ -10,9 +10,6 @@ using Umbraco.Web.Composing;
namespace Umbraco.Web.Mvc
{
- ///
- /// Provides a base class for front-end add-in controllers.
- ///
/// Migrated already to .Net Core without MergeModelStateToChildAction and MergeParentContextViewData action filters
/// TODO: Migrate MergeModelStateToChildAction and MergeParentContextViewData action filters
[MergeModelStateToChildAction]
@@ -26,197 +23,5 @@ namespace Umbraco.Web.Mvc
: base(umbracoContextAccessor, databaseFactory, services, appCaches,profilingLogger)
{ }
- ///
- /// Redirects to the Umbraco page with the given id
- ///
- ///
- ///
- protected RedirectToUmbracoPageResult RedirectToUmbracoPage(int pageId)
- {
- return new RedirectToUmbracoPageResult(pageId, Current.PublishedUrlProvider);
- }
-
- ///
- /// Redirects to the Umbraco page with the given id and passes provided querystring
- ///
- ///
- ///
- ///
- protected RedirectToUmbracoPageResult RedirectToUmbracoPage(int pageId, NameValueCollection queryStringValues)
- {
- return new RedirectToUmbracoPageResult(pageId, queryStringValues, Current.PublishedUrlProvider);
- }
-
- ///
- /// Redirects to the Umbraco page with the given id and passes provided querystring
- ///
- ///
- ///
- ///
- protected RedirectToUmbracoPageResult RedirectToUmbracoPage(int pageId, string queryString)
- {
- return new RedirectToUmbracoPageResult(pageId, queryString, Current.PublishedUrlProvider);
- }
-
- ///
- /// Redirects to the Umbraco page with the given id
- ///
- ///
- ///
- protected RedirectToUmbracoPageResult RedirectToUmbracoPage(Guid key)
- {
- return new RedirectToUmbracoPageResult(key);
- }
-
- ///
- /// Redirects to the Umbraco page with the given id and passes provided querystring
- ///
- ///
- ///
- ///
- protected RedirectToUmbracoPageResult RedirectToUmbracoPage(Guid key, NameValueCollection queryStringValues)
- {
- return new RedirectToUmbracoPageResult(key, queryStringValues);
- }
-
- ///
- /// Redirects to the Umbraco page with the given id and passes provided querystring
- ///
- ///
- ///
- ///
- protected RedirectToUmbracoPageResult RedirectToUmbracoPage(Guid key, string queryString)
- {
- return new RedirectToUmbracoPageResult(key, queryString);
- }
-
- ///
- /// Redirects to the Umbraco page with the given id
- ///
- ///
- ///
- protected RedirectToUmbracoPageResult RedirectToUmbracoPage(IPublishedContent publishedContent)
- {
- return new RedirectToUmbracoPageResult(publishedContent, Current.PublishedUrlProvider);
- }
-
- ///
- /// Redirects to the Umbraco page with the given id and passes provided querystring
- ///
- ///
- ///
- ///
- protected RedirectToUmbracoPageResult RedirectToUmbracoPage(IPublishedContent publishedContent, NameValueCollection queryStringValues)
- {
- return new RedirectToUmbracoPageResult(publishedContent, queryStringValues, Current.PublishedUrlProvider);
- }
-
- ///
- /// Redirects to the Umbraco page with the given id and passes provided querystring
- ///
- ///
- ///
- ///
- protected RedirectToUmbracoPageResult RedirectToUmbracoPage(IPublishedContent publishedContent, string queryString)
- {
- return new RedirectToUmbracoPageResult(publishedContent, queryString, Current.PublishedUrlProvider);
- }
-
- ///
- /// Redirects to the currently rendered Umbraco page
- ///
- ///
- protected RedirectToUmbracoPageResult RedirectToCurrentUmbracoPage()
- {
- return new RedirectToUmbracoPageResult(CurrentPage, Current.PublishedUrlProvider);
- }
-
- ///
- /// Redirects to the currently rendered Umbraco page and passes provided querystring
- ///
- ///
- ///
- protected RedirectToUmbracoPageResult RedirectToCurrentUmbracoPage(NameValueCollection queryStringValues)
- {
- return new RedirectToUmbracoPageResult(CurrentPage, queryStringValues, Current.PublishedUrlProvider);
- }
-
- ///
- /// Redirects to the currently rendered Umbraco page and passes provided querystring
- ///
- ///
- ///
- protected RedirectToUmbracoPageResult RedirectToCurrentUmbracoPage(string queryString)
- {
- return new RedirectToUmbracoPageResult(CurrentPage, queryString, Current.PublishedUrlProvider);
- }
-
- ///
- /// Redirects to the currently rendered Umbraco URL
- ///
- ///
- ///
- /// this is useful if you need to redirect
- /// to the current page but the current page is actually a rewritten URL normally done with something like
- /// Server.Transfer.
- ///
- protected RedirectToUmbracoUrlResult RedirectToCurrentUmbracoUrl()
- {
- return new RedirectToUmbracoUrlResult(UmbracoContext);
- }
-
- ///
- /// Returns the currently rendered Umbraco page
- ///
- ///
- protected UmbracoPageResult CurrentUmbracoPage()
- {
- return new UmbracoPageResult(ProfilingLogger);
- }
-
- ///
- /// Gets the current page.
- ///
- protected virtual IPublishedContent CurrentPage
- {
- get
- {
- var routeDefAttempt = TryGetRouteDefinitionFromAncestorViewContexts();
- if (routeDefAttempt.Success == false)
- throw routeDefAttempt.Exception;
-
- var routeDef = routeDefAttempt.Result;
- return routeDef.PublishedRequest.PublishedContent;
- }
- }
-
- ///
- /// we need to recursively find the route definition based on the parent view context
- ///
- ///
- ///
- /// We may have Child Actions within Child actions so we need to recursively look this up.
- /// see: http://issues.umbraco.org/issue/U4-1844
- ///
- private Attempt TryGetRouteDefinitionFromAncestorViewContexts()
- {
- var currentContext = ControllerContext;
- while (currentContext != null)
- {
- var currentRouteData = currentContext.RouteData;
- if (currentRouteData.Values.ContainsKey(Core.Constants.Web.UmbracoRouteDefinitionDataToken))
- {
- return Attempt.Succeed((RouteDefinition)currentRouteData.Values[Core.Constants.Web.UmbracoRouteDefinitionDataToken]);
- }
-
- currentContext = currentContext.IsChildAction
- ? currentContext.ParentActionViewContext
- : null;
- }
- return Attempt.Fail(
- new InvalidOperationException("Cannot find the Umbraco route definition in the route values, the request must be made in the context of an Umbraco request"));
- }
-
-
}
}
diff --git a/src/Umbraco.Web/Mvc/UmbracoPageResult.cs b/src/Umbraco.Web/Mvc/UmbracoPageResult.cs
deleted file mode 100644
index 580924b909..0000000000
--- a/src/Umbraco.Web/Mvc/UmbracoPageResult.cs
+++ /dev/null
@@ -1,140 +0,0 @@
-using System;
-using System.IO;
-using System.Web.Mvc;
-using System.Web.Routing;
-using Umbraco.Core;
-using Umbraco.Core.Logging;
-
-namespace Umbraco.Web.Mvc
-{
- ///
- /// Used by posted forms to proxy the result to the page in which the current URL matches on
- ///
- /// Migrated already to .Net Core
- public class UmbracoPageResult : ActionResult
- {
- private readonly IProfilingLogger _profilingLogger;
-
- public UmbracoPageResult(IProfilingLogger profilingLogger)
- {
- _profilingLogger = profilingLogger;
- }
-
- public override void ExecuteResult(ControllerContext context)
- {
- ResetRouteData(context.RouteData);
-
- ValidateRouteData(context.RouteData);
-
- var routeDef = (RouteDefinition)context.RouteData.Values[Umbraco.Core.Constants.Web.UmbracoRouteDefinitionDataToken];
-
- var factory = ControllerBuilder.Current.GetControllerFactory();
- context.RouteData.Values["action"] = routeDef.ActionName;
- ControllerBase controller = null;
-
- try
- {
- controller = CreateController(context, factory, routeDef);
-
- CopyControllerData(context, controller);
-
- ExecuteControllerAction(context, controller);
- }
- finally
- {
- CleanupController(controller, factory);
- }
- }
-
- ///
- /// Executes the controller action
- ///
- private void ExecuteControllerAction(ControllerContext context, IController controller)
- {
- using (_profilingLogger.TraceDuration("Executing Umbraco RouteDefinition controller", "Finished"))
- {
- controller.Execute(context.RequestContext);
- }
- }
-
- ///
- /// Since we could be returning the current page from a surface controller posted values in which the routing values are changed, we
- /// need to revert these values back to nothing in order for the normal page to render again.
- ///
- private static void ResetRouteData(RouteData routeData)
- {
- routeData.DataTokens["area"] = null;
- routeData.DataTokens["Namespaces"] = null;
- }
-
- ///
- /// Validate that the current page execution is not being handled by the normal umbraco routing system
- ///
- private static void ValidateRouteData(RouteData routeData)
- {
- if (routeData.Values.ContainsKey(Umbraco.Core.Constants.Web.UmbracoRouteDefinitionDataToken) == false)
- {
- throw new InvalidOperationException("Can only use " + typeof(UmbracoPageResult).Name +
- " in the context of an Http POST when using a SurfaceController form");
- }
- }
-
- ///
- /// Ensure ModelState, ViewData and TempData is copied across
- ///
- private static void CopyControllerData(ControllerContext context, ControllerBase controller)
- {
- controller.ViewData.ModelState.Merge(context.Controller.ViewData.ModelState);
-
- foreach (var d in context.Controller.ViewData)
- controller.ViewData[d.Key] = d.Value;
-
- //We cannot simply merge the temp data because during controller execution it will attempt to 'load' temp data
- // but since it has not been saved, there will be nothing to load and it will revert to nothing, so the trick is
- // to Save the state of the temp data first then it will automatically be picked up.
- // http://issues.umbraco.org/issue/U4-1339
-
- var targetController = controller as Controller;
- var sourceController = context.Controller as Controller;
- if (targetController != null && sourceController != null)
- {
- targetController.TempDataProvider = sourceController.TempDataProvider;
- targetController.TempData = sourceController.TempData;
- targetController.TempData.Save(sourceController.ControllerContext, sourceController.TempDataProvider);
- }
-
- }
-
- ///
- /// Creates a controller using the controller factory
- ///
- private static ControllerBase CreateController(ControllerContext context, IControllerFactory factory, RouteDefinition routeDef)
- {
- var controller = factory.CreateController(context.RequestContext, routeDef.ControllerName) as ControllerBase;
-
- if (controller == null)
- throw new InvalidOperationException("Could not create controller with name " + routeDef.ControllerName + ".");
-
- return controller;
- }
-
- ///
- /// Cleans up the controller by releasing it using the controller factory, and by disposing it.
- ///
- private static void CleanupController(IController controller, IControllerFactory factory)
- {
- if (controller != null)
- factory.ReleaseController(controller);
-
- if (controller != null)
- controller.DisposeIfDisposable();
- }
-
- private class DummyView : IView
- {
- public void Render(ViewContext viewContext, TextWriter writer)
- {
- }
- }
- }
-}
diff --git a/src/Umbraco.Web/Mvc/UmbracoRequireHttpsAttribute.cs b/src/Umbraco.Web/Mvc/UmbracoRequireHttpsAttribute.cs
deleted file mode 100644
index b88d1c0736..0000000000
--- a/src/Umbraco.Web/Mvc/UmbracoRequireHttpsAttribute.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System.Web.Mvc;
-using Umbraco.Core;
-using Umbraco.Web.Composing;
-
-namespace Umbraco.Web.Mvc
-{
- ///
- /// If Umbraco.Core.UseHttps property in web.config is set to true, this filter will redirect any http access to https.
- ///
- public class UmbracoRequireHttpsAttribute : RequireHttpsAttribute
- {
- ///
- /// If Umbraco.Core.UseHttps is true and we have a non-HTTPS request, handle redirect.
- ///
- /// Filter context
- protected override void HandleNonHttpsRequest(AuthorizationContext filterContext)
- {
- // If Umbraco.Core.UseHttps is set, let base method handle redirect. Otherwise, we don't care.
- if (/*Current.Configs.Global().UseHttps*/ false)
- {
- base.HandleNonHttpsRequest(filterContext);
- }
- }
-
- ///
- /// Check to see if HTTPS is currently being used if Umbraco.Core.UseHttps is true.
- ///
- /// Filter context
- public override void OnAuthorization(AuthorizationContext filterContext)
- {
- // If umbracoSSL is set, let base method handle checking for HTTPS. Otherwise, we don't care.
- if (/*Current.Configs.Global().UseHttps*/ false)
- {
- base.OnAuthorization(filterContext);
- }
- }
-
-
- }
-}
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index b8829a557d..5b6aa01f6d 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -180,10 +180,8 @@
-
-
@@ -216,7 +214,6 @@
-
True
True
@@ -224,7 +221,6 @@
-