re-enables the weird IgnorePublishedContentCollisions, simplifies IPublishedRouter interface (more flexible with request options),
This commit is contained in:
@@ -6,7 +6,9 @@ using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The result of Umbraco routing built with the <see cref="IPublishedRequestBuilder"/>
|
||||
/// </summary>
|
||||
public interface IPublishedRequest
|
||||
{
|
||||
/// <summary>
|
||||
@@ -15,11 +17,6 @@ namespace Umbraco.Web.Routing
|
||||
/// <remarks>The cleaned up Uri has no virtual directory, no trailing slash, no .aspx extension, etc.</remarks>
|
||||
Uri Uri { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the Umbraco Backoffice should ignore a collision for this request.
|
||||
/// </summary>
|
||||
bool IgnorePublishedContentCollisions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating the requested content.
|
||||
/// </summary>
|
||||
@@ -73,8 +70,22 @@ namespace Umbraco.Web.Routing
|
||||
IReadOnlyDictionary<string, string> Headers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating if the no-cache value should be added to the Cache-Control header
|
||||
/// Gets a value indicating whether the no-cache value should be added to the Cache-Control header
|
||||
/// </summary>
|
||||
bool SetNoCacheHeader { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the Umbraco Backoffice should ignore a collision for this request.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>This is an uncommon API used for edge cases with complex routing and would be used
|
||||
/// by developers to configure the request to disable collision checks in <see cref="UrlProviderExtensions"/>.</para>
|
||||
/// <para>This flag is based on previous Umbraco versions but it is not clear how this flag can be set by developers since
|
||||
/// collission checking only occurs in the back office which is launched by <see cref="IPublishedRouter.TryRouteRequestAsync(IPublishedRequestBuilder)"/>
|
||||
/// for which events do not execute.</para>
|
||||
/// <para>More can be read about this setting here: https://github.com/umbraco/Umbraco-CMS/pull/2148, https://issues.umbraco.org/issue/U4-10345
|
||||
/// but it's still unclear how this was used.</para>
|
||||
/// </remarks>
|
||||
bool IgnorePublishedContentCollisions { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,5 +138,19 @@ namespace Umbraco.Web.Routing
|
||||
/// Sets a dictionary of Headers to append to the Response object.
|
||||
/// </summary>
|
||||
IPublishedRequestBuilder SetHeaders(IReadOnlyDictionary<string, string> headers);
|
||||
|
||||
/// <summary>
|
||||
/// Can be called to configure the <see cref="IPublishedRequest"/> result to ignore URL collisions
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>This is an uncommon API used for edge cases with complex routing and would be used
|
||||
/// by developers to configure the request to disable collision checks in <see cref="UrlProviderExtensions"/>.</para>
|
||||
/// <para>This flag is based on previous Umbraco versions but it is not clear how this flag can be set by developers since
|
||||
/// collission checking only occurs in the back office which is launched by <see cref="IPublishedRouter.TryRouteRequestAsync(IPublishedRequestBuilder)"/>
|
||||
/// for which events do not execute.</para>
|
||||
/// <para>More can be read about this setting here: https://github.com/umbraco/Umbraco-CMS/pull/2148, https://issues.umbraco.org/issue/U4-10345
|
||||
/// but it's still unclear how this was used.</para>
|
||||
/// </remarks>
|
||||
void IgnorePublishedContentCollisions();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
@@ -10,8 +8,6 @@ namespace Umbraco.Web.Routing
|
||||
/// </summary>
|
||||
public interface IPublishedRouter
|
||||
{
|
||||
// TODO: consider this and UmbracoRouteValueTransformer - move some code around?
|
||||
|
||||
/// <summary>
|
||||
/// Creates a published request.
|
||||
/// </summary>
|
||||
@@ -20,18 +16,12 @@ namespace Umbraco.Web.Routing
|
||||
Task<IPublishedRequestBuilder> CreateRequestAsync(Uri uri);
|
||||
|
||||
/// <summary>
|
||||
/// Prepares a request for rendering.
|
||||
/// Sends a <see cref="IPublishedRequestBuilder"/> through the routing pipeline and builds a result.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>A value indicating whether the request was successfully prepared and can be rendered.</returns>
|
||||
Task<IPublishedRequest> RouteRequestAsync(IPublishedRequestBuilder request);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to route a request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>A value indicating whether the request can be routed to a document.</returns>
|
||||
Task<bool> TryRouteRequestAsync(IPublishedRequestBuilder request);
|
||||
/// <param name="options">The options.</param>
|
||||
/// <returns>The built <see cref="IPublishedRequest"/> instance.</returns>
|
||||
Task<IPublishedRequest> RouteRequestAsync(IPublishedRequestBuilder request, RouteRequestOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the request to "not found".
|
||||
|
||||
@@ -13,11 +13,9 @@ namespace Umbraco.Web.Routing
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PublishedRequest"/> class.
|
||||
/// </summary>
|
||||
public PublishedRequest(Uri uri, IPublishedContent publishedContent, bool isInternalRedirect, ITemplate template, DomainAndUri domain, CultureInfo culture, string redirectUrl, int? responseStatusCode, IReadOnlyList<string> cacheExtensions, IReadOnlyDictionary<string, string> headers, bool cacheabilityNoCache)
|
||||
public PublishedRequest(Uri uri, IPublishedContent publishedContent, bool isInternalRedirect, ITemplate template, DomainAndUri domain, CultureInfo culture, string redirectUrl, int? responseStatusCode, IReadOnlyList<string> cacheExtensions, IReadOnlyDictionary<string, string> headers, bool cacheabilityNoCache, bool ignorePublishedContentCollisions)
|
||||
{
|
||||
Uri = uri ?? throw new ArgumentNullException(nameof(uri));
|
||||
// TODO: What is this?
|
||||
//IgnorePublishedContentCollisions = ignorePublishedContentCollisions;
|
||||
PublishedContent = publishedContent;
|
||||
IsInternalRedirect = isInternalRedirect;
|
||||
Template = template;
|
||||
@@ -28,6 +26,7 @@ namespace Umbraco.Web.Routing
|
||||
CacheExtensions = cacheExtensions;
|
||||
Headers = headers;
|
||||
SetNoCacheHeader = cacheabilityNoCache;
|
||||
IgnorePublishedContentCollisions = ignorePublishedContentCollisions;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Umbraco.Web.Routing
|
||||
private string _redirectUrl;
|
||||
private HttpStatusCode? _responseStatus;
|
||||
private IPublishedContent _publishedContent;
|
||||
private bool _ignorePublishedContentCollisions;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PublishedRequestBuilder"/> class.
|
||||
@@ -70,7 +71,8 @@ namespace Umbraco.Web.Routing
|
||||
_responseStatus.HasValue ? (int?)_responseStatus : null,
|
||||
_cacheExtensions,
|
||||
_headers,
|
||||
_cacheability);
|
||||
_cacheability,
|
||||
_ignorePublishedContentCollisions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPublishedRequestBuilder SetNoCacheHeader(bool cacheability)
|
||||
@@ -190,5 +192,8 @@ namespace Umbraco.Web.Routing
|
||||
Template = model;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void IgnorePublishedContentCollisions() => _ignorePublishedContentCollisions = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,26 +100,25 @@ namespace Umbraco.Web.Routing
|
||||
return publishedRequestBuilder;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<bool> TryRouteRequestAsync(IPublishedRequestBuilder request)
|
||||
private IPublishedRequest TryRouteRequest(IPublishedRequestBuilder request)
|
||||
{
|
||||
FindDomain(request);
|
||||
|
||||
// TODO: This was ported from v8 but how could it possibly have a redirect here?
|
||||
if (request.IsRedirect())
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
return request.Build();
|
||||
}
|
||||
|
||||
// TODO: This was ported from v8 but how could it possibly have content here?
|
||||
if (request.HasPublishedContent())
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
return request.Build();
|
||||
}
|
||||
|
||||
FindPublishedContent(request);
|
||||
|
||||
return Task.FromResult(request.Build().Success());
|
||||
return request.Build();
|
||||
}
|
||||
|
||||
private void SetVariationContext(CultureInfo culture)
|
||||
@@ -138,11 +137,18 @@ namespace Umbraco.Web.Routing
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IPublishedRequest> RouteRequestAsync(IPublishedRequestBuilder request)
|
||||
public async Task<IPublishedRequest> RouteRequestAsync(IPublishedRequestBuilder request, RouteRequestOptions options)
|
||||
{
|
||||
// outbound routing performs different/simpler logic
|
||||
if (options.RouteDirection == RouteDirection.Outbound)
|
||||
{
|
||||
return TryRouteRequest(request);
|
||||
}
|
||||
|
||||
// find domain
|
||||
FindDomain(request);
|
||||
|
||||
// TODO: This was ported from v8 but how could it possibly have a redirect here?
|
||||
// if request has been flagged to redirect then return
|
||||
// whoever called us is in charge of actually redirecting
|
||||
if (request.IsRedirect())
|
||||
@@ -156,7 +162,8 @@ namespace Umbraco.Web.Routing
|
||||
// find the published content if it's not assigned. This could be manually assigned with a custom route handler, or
|
||||
// with something like EnsurePublishedContentRequestAttribute or UmbracoVirtualNodeRouteHandler. Those in turn call this method
|
||||
// to setup the rest of the pipeline but we don't want to run the finders since there's one assigned.
|
||||
if (request.PublishedContent == null)
|
||||
// TODO: This might very well change when we look into porting custom routes in netcore like EnsurePublishedContentRequestAttribute or UmbracoVirtualNodeRouteHandler.
|
||||
if (!request.HasPublishedContent())
|
||||
{
|
||||
// find the document & template
|
||||
FindPublishedContentAndTemplate(request);
|
||||
|
||||
18
src/Umbraco.Core/Routing/RouteDirection.cs
Normal file
18
src/Umbraco.Core/Routing/RouteDirection.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
/// <summary>
|
||||
/// The direction of a route
|
||||
/// </summary>
|
||||
public enum RouteDirection
|
||||
{
|
||||
/// <summary>
|
||||
/// An inbound route used to map a URL to a content item
|
||||
/// </summary>
|
||||
Inbound = 1,
|
||||
|
||||
/// <summary>
|
||||
/// An outbound route used to generate a URL for a content item
|
||||
/// </summary>
|
||||
Outbound = 2
|
||||
}
|
||||
}
|
||||
29
src/Umbraco.Core/Routing/RouteRequestOptions.cs
Normal file
29
src/Umbraco.Core/Routing/RouteRequestOptions.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
/// <summary>
|
||||
/// Options for routing an Umbraco request
|
||||
/// </summary>
|
||||
public struct RouteRequestOptions : IEquatable<RouteRequestOptions>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RouteRequestOptions"/> struct.
|
||||
/// </summary>
|
||||
public RouteRequestOptions(RouteDirection direction) => RouteDirection = direction;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="RouteDirection"/>
|
||||
/// </summary>
|
||||
public RouteDirection RouteDirection { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object obj) => obj is RouteRequestOptions options && Equals(options);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(RouteRequestOptions other) => RouteDirection == other.RouteDirection;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode() => 15391035 + RouteDirection.GetHashCode();
|
||||
}
|
||||
}
|
||||
@@ -204,20 +204,19 @@ namespace Umbraco.Web.Routing
|
||||
}
|
||||
|
||||
uri = uriUtility.UriToUmbraco(uri);
|
||||
IPublishedRequestBuilder pcr = await publishedRouter.CreateRequestAsync(uri);
|
||||
var routeResult = await publishedRouter.TryRouteRequestAsync(pcr);
|
||||
IPublishedRequestBuilder builder = await publishedRouter.CreateRequestAsync(uri);
|
||||
IPublishedRequest pcr = await publishedRouter.RouteRequestAsync(builder, new RouteRequestOptions(RouteDirection.Outbound));
|
||||
|
||||
if (pcr.PublishedContent == null)
|
||||
if (!pcr.HasPublishedContent())
|
||||
{
|
||||
var urlInfo = UrlInfo.Message(textService.Localize("content/routeErrorCannotRoute"), culture);
|
||||
return Attempt.Succeed(urlInfo);
|
||||
}
|
||||
|
||||
// TODO: What is this?
|
||||
//if (pcr.IgnorePublishedContentCollisions)
|
||||
//{
|
||||
// return false;
|
||||
//}
|
||||
if (pcr.IgnorePublishedContentCollisions)
|
||||
{
|
||||
return Attempt<UrlInfo>.Fail();
|
||||
}
|
||||
|
||||
if (pcr.PublishedContent.Id != content.Id)
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@ using Umbraco.Extensions;
|
||||
using Umbraco.Web.Common.Routing;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Web.Website.Controllers;
|
||||
using RouteDirection = Umbraco.Web.Routing.RouteDirection;
|
||||
|
||||
namespace Umbraco.Web.Website.Routing
|
||||
{
|
||||
@@ -112,7 +113,7 @@ namespace Umbraco.Web.Website.Routing
|
||||
// an immutable object. The only way to make this better would be to have a RouteRequest
|
||||
// as part of UmbracoContext but then it will require a PublishedRouter dependency so not sure that's worth it.
|
||||
// Maybe could be a one-time Set method instead?
|
||||
IPublishedRequest publishedRequest = umbracoContext.PublishedRequest = await _publishedRouter.RouteRequestAsync(requestBuilder);
|
||||
IPublishedRequest publishedRequest = umbracoContext.PublishedRequest = await _publishedRouter.RouteRequestAsync(requestBuilder, new RouteRequestOptions(RouteDirection.Inbound));
|
||||
|
||||
return publishedRequest;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Web.Composing;
|
||||
using Umbraco.Web.Routing;
|
||||
using RouteDirection = Umbraco.Web.Routing.RouteDirection;
|
||||
|
||||
namespace Umbraco.Web
|
||||
{
|
||||
@@ -136,7 +137,7 @@ namespace Umbraco.Web
|
||||
// instantiate, prepare and process the published content request
|
||||
// important to use CleanedUmbracoUrl - lowercase path-only version of the current URL
|
||||
var requestBuilder = _publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl).Result;
|
||||
var request = umbracoContext.PublishedRequest = _publishedRouter.RouteRequestAsync(requestBuilder).Result;
|
||||
var request = umbracoContext.PublishedRequest = _publishedRouter.RouteRequestAsync(requestBuilder, new RouteRequestOptions(RouteDirection.Inbound)).Result;
|
||||
|
||||
// NOTE: This has been ported to netcore
|
||||
// HandleHttpResponseStatus returns a value indicating that the request should
|
||||
|
||||
Reference in New Issue
Block a user