removes ResponseStatusDescription and others that aren't used, ports the not found handler, ports redirects, headers, etc...
This commit is contained in:
@@ -60,14 +60,7 @@ namespace Umbraco.Web.Routing
|
||||
/// </summary>
|
||||
/// <remarks>Does not actually set the http response status code, only registers that the response
|
||||
/// should use the specified code. The code will or will not be used, in due time.</remarks>
|
||||
int ResponseStatusCode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content request http response status description.
|
||||
/// </summary>
|
||||
/// <remarks>Does not actually set the http response status description, only registers that the response
|
||||
/// should use the specified description. The description will or will not be used, in due time.</remarks>
|
||||
string ResponseStatusDescription { get; }
|
||||
int? ResponseStatusCode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of Extensions to append to the Response.Cache object.
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Umbraco.Web.Routing
|
||||
/// <summary>
|
||||
/// Gets the content request http response status code.
|
||||
/// </summary>
|
||||
int ResponseStatusCode { get; }
|
||||
int? ResponseStatusCode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current <see cref="IPublishedContent"/> assigned (if any)
|
||||
@@ -77,7 +77,7 @@ namespace Umbraco.Web.Routing
|
||||
/// <param name="content">The requested content.</param>
|
||||
/// <remarks>Depending on <c>UmbracoSettings.InternalRedirectPreservesTemplate</c>, will
|
||||
/// preserve or reset the template, if any.</remarks>
|
||||
IPublishedRequestBuilder SetInternalRedirectPublishedContent(IPublishedContent content);
|
||||
IPublishedRequestBuilder SetInternalRedirectPublishedContent(IPublishedContent content); // TODO: Need to figure this one out
|
||||
|
||||
/// <summary>
|
||||
/// Tries to set the template to use to display the requested content.
|
||||
@@ -97,11 +97,6 @@ namespace Umbraco.Web.Routing
|
||||
/// <remarks>Setting the template does refresh <c>RenderingEngine</c>.</remarks>
|
||||
IPublishedRequestBuilder SetTemplate(ITemplate template);
|
||||
|
||||
/// <summary>
|
||||
/// Resets the template.
|
||||
/// </summary>
|
||||
IPublishedRequestBuilder ResetTemplate();
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the content request should trigger a permanent redirect (301).
|
||||
/// </summary>
|
||||
@@ -123,11 +118,10 @@ namespace Umbraco.Web.Routing
|
||||
/// Sets the http response status code, along with an optional associated description.
|
||||
/// </summary>
|
||||
/// <param name="code">The http status code.</param>
|
||||
/// <param name="description">The description.</param>
|
||||
/// <remarks>Does not actually set the http response status code and description, only registers that
|
||||
/// the response should use the specified code and description. The code and description will or will
|
||||
/// not be used, in due time.</remarks>
|
||||
IPublishedRequestBuilder SetResponseStatus(int code, string description = null);
|
||||
IPublishedRequestBuilder SetResponseStatus(int code);
|
||||
|
||||
IPublishedRequestBuilder SetCacheabilityNoCache(bool cacheability);
|
||||
|
||||
@@ -140,16 +134,5 @@ namespace Umbraco.Web.Routing
|
||||
/// Sets a dictionary of Headers to append to the Response object.
|
||||
/// </summary>
|
||||
IPublishedRequestBuilder SetHeaders(IReadOnlyDictionary<string, string> headers);
|
||||
|
||||
/// <summary>
|
||||
/// Sets a value indicating that the requested content could not be found.
|
||||
/// </summary>
|
||||
/// <remarks>This is set in the <c>PublishedContentRequestBuilder</c> and can also be used in
|
||||
/// custom content finders or <c>Prepared</c> event handlers, where we want to allow developers
|
||||
/// to indicate a request is 404 but not to cancel it.</remarks>
|
||||
IPublishedRequestBuilder SetIs404(bool is404);
|
||||
|
||||
// TODO: This seems to be the same as is404?
|
||||
//IPublishedRequestBuilder UpdateToNotFound();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,20 +16,19 @@ namespace Umbraco.Web.Routing
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PublishedRequest"/> class.
|
||||
/// </summary>
|
||||
public PublishedRequest(Uri uri, /*bool ignorePublishedContentCollisions, */IPublishedContent publishedContent, bool isInternalRedirectPublishedContent, ITemplate template, DomainAndUri domain, CultureInfo culture, string redirectUrl, int responseStatusCode, string responseStatusDescription, IReadOnlyList<string> cacheExtensions, IReadOnlyDictionary<string, string> headers, bool cacheabilityNoCache)
|
||||
public PublishedRequest(Uri uri, /*bool ignorePublishedContentCollisions, */IPublishedContent publishedContent, bool isInternalRedirectPublishedContent, ITemplate template, DomainAndUri domain, CultureInfo culture, string redirectUrl, int? responseStatusCode, IReadOnlyList<string> cacheExtensions, IReadOnlyDictionary<string, string> headers, bool cacheabilityNoCache)
|
||||
{
|
||||
Uri = uri ?? throw new ArgumentNullException(nameof(uri));
|
||||
//IgnorePublishedContentCollisions = ignorePublishedContentCollisions;
|
||||
PublishedContent = publishedContent ?? throw new ArgumentNullException(nameof(publishedContent));
|
||||
PublishedContent = publishedContent;
|
||||
IsInternalRedirectPublishedContent = isInternalRedirectPublishedContent;
|
||||
Template = template ?? throw new ArgumentNullException(nameof(template));
|
||||
Domain = domain ?? throw new ArgumentNullException(nameof(domain));
|
||||
Template = template;
|
||||
Domain = domain;
|
||||
Culture = culture ?? throw new ArgumentNullException(nameof(culture));
|
||||
RedirectUrl = redirectUrl ?? throw new ArgumentNullException(nameof(redirectUrl));
|
||||
RedirectUrl = redirectUrl;
|
||||
ResponseStatusCode = responseStatusCode;
|
||||
ResponseStatusDescription = responseStatusDescription ?? throw new ArgumentNullException(nameof(responseStatusDescription));
|
||||
CacheExtensions = cacheExtensions ?? throw new ArgumentNullException(nameof(cacheExtensions));
|
||||
Headers = headers ?? throw new ArgumentNullException(nameof(headers));
|
||||
CacheExtensions = cacheExtensions;
|
||||
Headers = headers;
|
||||
CacheabilityNoCache = cacheabilityNoCache;
|
||||
}
|
||||
|
||||
@@ -42,9 +41,6 @@ namespace Umbraco.Web.Routing
|
||||
/// <inheritdoc/>
|
||||
public IPublishedContent PublishedContent { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPublishedContent InitialPublishedContent { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsInternalRedirectPublishedContent { get; }
|
||||
|
||||
@@ -61,10 +57,7 @@ namespace Umbraco.Web.Routing
|
||||
public string RedirectUrl { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int ResponseStatusCode { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string ResponseStatusDescription { get; }
|
||||
public int? ResponseStatusCode { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IReadOnlyList<string> CacheExtensions { get; }
|
||||
|
||||
@@ -17,19 +17,19 @@ namespace Umbraco.Web.Routing
|
||||
private IReadOnlyList<string> _cacheExtensions;
|
||||
private IPublishedContent _internalRedirectContent;
|
||||
private string _redirectUrl;
|
||||
private HttpStatusCode _responseStatus = HttpStatusCode.NotFound;
|
||||
private string _responseDesc;
|
||||
private HttpStatusCode? _responseStatus;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PublishedRequestBuilder"/> class.
|
||||
/// </summary>
|
||||
public PublishedRequestBuilder(IFileService fileService)
|
||||
public PublishedRequestBuilder(Uri uri, IFileService fileService)
|
||||
{
|
||||
Uri = uri;
|
||||
_fileService = fileService;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Uri Uri { get; private set; }
|
||||
public Uri Uri { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DomainAndUri Domain { get; private set; }
|
||||
@@ -44,7 +44,7 @@ namespace Umbraco.Web.Routing
|
||||
public bool IsInternalRedirectPublishedContent { get; private set; } // TODO: Not sure what this is yet
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int ResponseStatusCode => (int)_responseStatus;
|
||||
public int? ResponseStatusCode => _responseStatus.HasValue ? (int?)_responseStatus : null;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPublishedContent PublishedContent { get; private set; }
|
||||
@@ -58,19 +58,11 @@ namespace Umbraco.Web.Routing
|
||||
Domain,
|
||||
Culture,
|
||||
_redirectUrl,
|
||||
(int)_responseStatus,
|
||||
_responseDesc,
|
||||
_responseStatus.HasValue ? (int?)_responseStatus : null,
|
||||
_cacheExtensions,
|
||||
_headers,
|
||||
_cacheability);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPublishedRequestBuilder ResetTemplate()
|
||||
{
|
||||
Template = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPublishedRequestBuilder SetCacheabilityNoCache(bool cacheability)
|
||||
{
|
||||
@@ -113,13 +105,6 @@ namespace Umbraco.Web.Routing
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPublishedRequestBuilder SetIs404(bool is404)
|
||||
{
|
||||
_responseStatus = HttpStatusCode.NotFound;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPublishedRequestBuilder SetPublishedContent(IPublishedContent content)
|
||||
{
|
||||
@@ -144,10 +129,9 @@ namespace Umbraco.Web.Routing
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPublishedRequestBuilder SetResponseStatus(int code, string description = null)
|
||||
public IPublishedRequestBuilder SetResponseStatus(int code)
|
||||
{
|
||||
_responseStatus = (HttpStatusCode)code;
|
||||
_responseDesc = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,14 +2,42 @@ using System.Net;
|
||||
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
|
||||
public static class PublishedRequestExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the <see cref="UmbracoRouteResult"/>
|
||||
/// </summary>
|
||||
public static UmbracoRouteResult GetRouteResult(this IPublishedRequest publishedRequest)
|
||||
{
|
||||
if (publishedRequest.IsRedirect())
|
||||
{
|
||||
return UmbracoRouteResult.Redirect;
|
||||
}
|
||||
|
||||
if (!publishedRequest.HasPublishedContent())
|
||||
{
|
||||
return UmbracoRouteResult.NotFound;
|
||||
}
|
||||
|
||||
return UmbracoRouteResult.Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the request was successfully routed
|
||||
/// </summary>
|
||||
public static bool Success(this IPublishedRequest publishedRequest)
|
||||
=> !publishedRequest.IsRedirect() && publishedRequest.HasPublishedContent();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the response status to be 404 not found
|
||||
/// </summary>
|
||||
public static IPublishedRequestBuilder SetIs404(this IPublishedRequestBuilder publishedRequest)
|
||||
{
|
||||
publishedRequest.SetResponseStatus((int)HttpStatusCode.NotFound);
|
||||
return publishedRequest;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the content request has a content.
|
||||
/// </summary>
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace Umbraco.Web.Routing
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IPublishedRequestBuilder CreateRequest(Uri uri) => new PublishedRequestBuilder(_fileService);
|
||||
public IPublishedRequestBuilder CreateRequest(Uri uri) => new PublishedRequestBuilder(uri, _fileService);
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool TryRouteRequest(IPublishedRequestBuilder request)
|
||||
@@ -106,6 +106,10 @@ namespace Umbraco.Web.Routing
|
||||
/// <inheritdoc />
|
||||
public IPublishedRequest RouteRequest(IPublishedRequestBuilder request)
|
||||
{
|
||||
//// trigger the Preparing event - at that point anything can still be changed
|
||||
//// the idea is that it is possible to change the uri
|
||||
//request.OnPreparing();
|
||||
|
||||
// find domain
|
||||
FindDomain(request);
|
||||
|
||||
@@ -411,7 +415,7 @@ namespace Umbraco.Web.Routing
|
||||
// handle not found
|
||||
if (request.PublishedContent == null)
|
||||
{
|
||||
request.SetIs404(true);
|
||||
request.SetIs404();
|
||||
_logger.LogDebug("HandlePublishedContent: No document, try last chance lookup");
|
||||
|
||||
// if it fails then give up, there isn't much more that we can do
|
||||
|
||||
20
src/Umbraco.Core/Routing/UmbracoRouteResult.cs
Normal file
20
src/Umbraco.Core/Routing/UmbracoRouteResult.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
public enum UmbracoRouteResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Routing was successful and a content item was matched
|
||||
/// </summary>
|
||||
Success,
|
||||
|
||||
/// <summary>
|
||||
/// A redirection took place
|
||||
/// </summary>
|
||||
Redirect,
|
||||
|
||||
/// <summary>
|
||||
/// Nothing matched
|
||||
/// </summary>
|
||||
NotFound
|
||||
}
|
||||
}
|
||||
@@ -111,7 +111,7 @@ namespace Umbraco.Web.Routing
|
||||
|
||||
frequest
|
||||
.SetPublishedContent(content)
|
||||
.SetIs404(true);
|
||||
.SetIs404();
|
||||
|
||||
return content != null;
|
||||
}
|
||||
|
||||
@@ -12,9 +12,11 @@ using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Common.ModelBinders;
|
||||
using Umbraco.Web.Common.Routing;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.ModelBinders
|
||||
{
|
||||
@@ -211,9 +213,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.ModelBinders
|
||||
/// </summary>
|
||||
private ModelBindingContext CreateBindingContextForUmbracoRequest(Type modelType, IPublishedContent publishedContent)
|
||||
{
|
||||
var builder = new PublishedRequestBuilder(new Uri("https://example.com"), Mock.Of<IFileService>());
|
||||
builder.SetPublishedContent(publishedContent);
|
||||
IPublishedRequest publishedRequest = builder.Build();
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var routeData = new RouteData();
|
||||
routeData.Values.Add(Constants.Web.UmbracoRouteDefinitionDataToken, new UmbracoRouteValues(publishedContent));
|
||||
routeData.Values.Add(Constants.Web.UmbracoRouteDefinitionDataToken, new UmbracoRouteValues(publishedRequest));
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -162,8 +162,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers
|
||||
var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext);
|
||||
|
||||
IPublishedContent content = Mock.Of<IPublishedContent>(publishedContent => publishedContent.Id == 12345);
|
||||
var builder = new PublishedRequestBuilder(umbracoContext.CleanedUmbracoUrl, Mock.Of<IFileService>());
|
||||
builder.SetPublishedContent(content);
|
||||
IPublishedRequest publishedRequest = builder.Build();
|
||||
|
||||
var routeDefinition = new UmbracoRouteValues(content);
|
||||
var routeDefinition = new UmbracoRouteValues(publishedRequest);
|
||||
|
||||
var routeData = new RouteData();
|
||||
routeData.Values.Add(CoreConstants.Web.UmbracoRouteDefinitionDataToken, routeDefinition);
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Web.Common.ActionsResults
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the Umbraco not found result
|
||||
/// </summary>
|
||||
public class PublishedContentNotFoundResult : IActionResult
|
||||
{
|
||||
private readonly IUmbracoContext _umbracoContext;
|
||||
private readonly string _message;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PublishedContentNotFoundResult"/> class.
|
||||
/// </summary>
|
||||
public PublishedContentNotFoundResult(IUmbracoContext umbracoContext, string message = null)
|
||||
{
|
||||
_umbracoContext = umbracoContext;
|
||||
_message = message;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task ExecuteResultAsync(ActionContext context)
|
||||
{
|
||||
HttpResponse response = context.HttpContext.Response;
|
||||
|
||||
response.Clear();
|
||||
|
||||
response.StatusCode = StatusCodes.Status404NotFound;
|
||||
|
||||
IPublishedRequest frequest = _umbracoContext.PublishedRequest;
|
||||
var reason = "Cannot render the page at URL '{0}'.";
|
||||
if (frequest.HasPublishedContent() == false)
|
||||
{
|
||||
reason = "No umbraco document matches the URL '{0}'.";
|
||||
}
|
||||
else if (frequest.HasTemplate() == false)
|
||||
{
|
||||
reason = "No template exists to render the document at URL '{0}'.";
|
||||
}
|
||||
|
||||
await response.WriteAsync("<html><body><h1>Page not found</h1>");
|
||||
await response.WriteAsync("<h2>");
|
||||
await response.WriteAsync(string.Format(reason, WebUtility.HtmlEncode(_umbracoContext.OriginalRequestUrl.PathAndQuery)));
|
||||
await response.WriteAsync("</h2>");
|
||||
if (string.IsNullOrWhiteSpace(_message) == false)
|
||||
{
|
||||
await response.WriteAsync("<p>" + _message + "</p>");
|
||||
}
|
||||
|
||||
await response.WriteAsync("<p>This page can be replaced with a custom 404. Check the documentation for \"custom 404\".</p>");
|
||||
await response.WriteAsync("<p style=\"border-top: 1px solid #ccc; padding-top: 10px\"><small>This page is intentionally left ugly ;-)</small></p>");
|
||||
await response.WriteAsync("</body></html>");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Umbraco.Web.Common.Routing;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Web.Common.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Deals with custom headers for the umbraco request
|
||||
/// </summary>
|
||||
internal class PublishedRequestFilterAttribute : ResultFilterAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the <see cref="UmbracoRouteValues"/>
|
||||
/// </summary>
|
||||
protected UmbracoRouteValues GetUmbracoRouteValues(ResultExecutingContext context)
|
||||
{
|
||||
if (!context.RouteData.Values.TryGetValue(Core.Constants.Web.UmbracoRouteDefinitionDataToken, out var def))
|
||||
{
|
||||
throw new InvalidOperationException($"No route value found with key {Core.Constants.Web.UmbracoRouteDefinitionDataToken}");
|
||||
}
|
||||
|
||||
return (UmbracoRouteValues)def;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deals with custom headers for the umbraco request
|
||||
/// </summary>
|
||||
public override void OnResultExecuting(ResultExecutingContext context)
|
||||
{
|
||||
UmbracoRouteValues routeVals = GetUmbracoRouteValues(context);
|
||||
IPublishedRequest pcr = routeVals.PublishedRequest;
|
||||
|
||||
// now we can deal with headers, etc...
|
||||
if (pcr.ResponseStatusCode.HasValue)
|
||||
{
|
||||
// set status code -- even for redirects
|
||||
context.HttpContext.Response.StatusCode = pcr.ResponseStatusCode.Value;
|
||||
}
|
||||
|
||||
AddCacheControlHeaders(context, pcr);
|
||||
|
||||
if (pcr.Headers != null)
|
||||
{
|
||||
foreach (KeyValuePair<string, string> header in pcr.Headers)
|
||||
{
|
||||
context.HttpContext.Response.Headers.Append(header.Key, header.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddCacheControlHeaders(ResultExecutingContext context, IPublishedRequest pcr)
|
||||
{
|
||||
var cacheControlHeaders = new List<string>();
|
||||
|
||||
if (pcr.CacheabilityNoCache)
|
||||
{
|
||||
cacheControlHeaders.Add("no-cache");
|
||||
}
|
||||
|
||||
if (pcr.CacheExtensions != null)
|
||||
{
|
||||
foreach (var cacheExtension in pcr.CacheExtensions)
|
||||
{
|
||||
cacheControlHeaders.Add(cacheExtension);
|
||||
}
|
||||
}
|
||||
|
||||
if (cacheControlHeaders.Count > 0)
|
||||
{
|
||||
context.HttpContext.Response.Headers["Cache-Control"] = string.Join(", ", cacheControlHeaders);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.ViewEngines;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Web.Common.ActionsResults;
|
||||
using Umbraco.Web.Common.Filters;
|
||||
using Umbraco.Web.Common.Routing;
|
||||
using Umbraco.Web.Models;
|
||||
@@ -11,30 +13,50 @@ using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Web.Common.Controllers
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Represents the default front-end rendering controller.
|
||||
/// </summary>
|
||||
[ModelBindingException]
|
||||
[PublishedRequestFilter]
|
||||
public class RenderController : UmbracoController, IRenderController
|
||||
{
|
||||
private readonly ILogger<RenderController> _logger;
|
||||
private readonly ICompositeViewEngine _compositeViewEngine;
|
||||
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
|
||||
private UmbracoRouteValues _umbracoRouteValues;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RenderController"/> class.
|
||||
/// </summary>
|
||||
public RenderController(ILogger<RenderController> logger, ICompositeViewEngine compositeViewEngine)
|
||||
public RenderController(ILogger<RenderController> logger, ICompositeViewEngine compositeViewEngine, IUmbracoContextAccessor umbracoContextAccessor)
|
||||
{
|
||||
_logger = logger;
|
||||
_compositeViewEngine = compositeViewEngine;
|
||||
_umbracoContextAccessor = umbracoContextAccessor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current content item.
|
||||
/// </summary>
|
||||
protected IPublishedContent CurrentPage => UmbracoRouteValues.PublishedContent;
|
||||
protected IPublishedContent CurrentPage
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!UmbracoRouteValues.PublishedRequest.HasPublishedContent())
|
||||
{
|
||||
// This will never be accessed this way since the controller will handle redirects and not founds
|
||||
// before this can be accessed but we need to be explicit.
|
||||
throw new InvalidOperationException("There is no published content found in the request");
|
||||
}
|
||||
|
||||
return UmbracoRouteValues.PublishedRequest.PublishedContent;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the umbraco context
|
||||
/// </summary>
|
||||
protected IUmbracoContext UmbracoContext => _umbracoContextAccessor.UmbracoContext;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="UmbracoRouteValues"/>
|
||||
@@ -95,5 +117,41 @@ namespace Umbraco.Web.Common.Controllers
|
||||
/// The default action to render the front-end view.
|
||||
/// </summary>
|
||||
public virtual IActionResult Index() => CurrentTemplate(new ContentModel(CurrentPage));
|
||||
|
||||
/// <summary>
|
||||
/// Before the controller executes we will handle redirects and not founds
|
||||
/// </summary>
|
||||
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
||||
{
|
||||
IPublishedRequest pcr = UmbracoRouteValues.PublishedRequest;
|
||||
|
||||
_logger.LogDebug(
|
||||
"Response status: Redirect={Redirect}, Is404={Is404}, StatusCode={ResponseStatusCode}",
|
||||
pcr.IsRedirect() ? (pcr.IsRedirectPermanent() ? "permanent" : "redirect") : "none",
|
||||
pcr.Is404() ? "true" : "false",
|
||||
pcr.ResponseStatusCode);
|
||||
|
||||
UmbracoRouteResult routeStatus = pcr.GetRouteResult();
|
||||
switch (routeStatus)
|
||||
{
|
||||
case UmbracoRouteResult.Redirect:
|
||||
|
||||
// set the redirect result and do not call next to short circuit
|
||||
context.Result = pcr.IsRedirectPermanent()
|
||||
? RedirectPermanent(pcr.RedirectUrl)
|
||||
: Redirect(pcr.RedirectUrl);
|
||||
break;
|
||||
case UmbracoRouteResult.NotFound:
|
||||
|
||||
// set the redirect result and do not call next to short circuit
|
||||
context.Result = new PublishedContentNotFoundResult(UmbracoContext);
|
||||
break;
|
||||
case UmbracoRouteResult.Success:
|
||||
default:
|
||||
// continue normally
|
||||
await next();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Umbraco.Web.Common.ModelBinders
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
BindModel(bindingContext, umbracoRouteValues.PublishedContent, bindingContext.ModelType);
|
||||
BindModel(bindingContext, umbracoRouteValues.PublishedRequest.PublishedContent, bindingContext.ModelType);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Umbraco.Web.Common.Routing
|
||||
/// Initializes a new instance of the <see cref="UmbracoRouteValues"/> class.
|
||||
/// </summary>
|
||||
public UmbracoRouteValues(
|
||||
IPublishedContent publishedContent,
|
||||
IPublishedRequest publishedRequest,
|
||||
string controllerName = null,
|
||||
Type controllerType = null,
|
||||
string actionName = DefaultActionName,
|
||||
@@ -29,7 +29,7 @@ namespace Umbraco.Web.Common.Routing
|
||||
{
|
||||
ControllerName = controllerName ?? ControllerExtensions.GetControllerName<RenderController>();
|
||||
ControllerType = controllerType ?? typeof(RenderController);
|
||||
PublishedContent = publishedContent;
|
||||
PublishedRequest = publishedRequest;
|
||||
HasHijackedRoute = hasHijackedRoute;
|
||||
ActionName = actionName;
|
||||
TemplateName = templateName;
|
||||
@@ -56,9 +56,9 @@ namespace Umbraco.Web.Common.Routing
|
||||
public Type ControllerType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IPublishedContent"/>
|
||||
/// Gets the <see cref="IPublishedRequest"/>
|
||||
/// </summary>
|
||||
public IPublishedContent PublishedContent { get; }
|
||||
public IPublishedRequest PublishedRequest { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current request has a hijacked route/user controller routed for it
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
@@ -12,6 +12,7 @@ using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Web.Website.ActionResults
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Redirects to an Umbraco page by Id or Entity
|
||||
/// </summary>
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Umbraco.Web.Website.Controllers
|
||||
}
|
||||
|
||||
var routeDef = routeDefAttempt.Result;
|
||||
return routeDef.PublishedContent;
|
||||
return routeDef.PublishedRequest.PublishedContent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,6 @@ namespace Umbraco.Web.Website.DependencyInjection
|
||||
/// </summary>
|
||||
public static IUmbracoBuilder AddWebsite(this IUmbracoBuilder builder)
|
||||
{
|
||||
builder.Services.AddUnique<NoContentRoutes>();
|
||||
|
||||
builder.WithCollectionBuilder<SurfaceControllerTypeCollectionBuilder>()
|
||||
.Add(builder.TypeLoader.GetSurfaceControllers());
|
||||
|
||||
|
||||
@@ -37,9 +37,6 @@ namespace Umbraco.Extensions
|
||||
{
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
NoContentRoutes noContentRoutes = app.ApplicationServices.GetRequiredService<NoContentRoutes>();
|
||||
noContentRoutes.CreateRoutes(endpoints);
|
||||
|
||||
endpoints.MapDynamicControllerRoute<UmbracoRouteValueTransformer>("/{**slug}");
|
||||
});
|
||||
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.Models;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Web.Common.Routing;
|
||||
|
||||
namespace Umbraco.Web.Website.Routing
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates route for the no content page
|
||||
/// </summary>
|
||||
public class NoContentRoutes : IAreaRoutes
|
||||
{
|
||||
private readonly IRuntimeState _runtimeState;
|
||||
private readonly string _umbracoPathSegment;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NoContentRoutes"/> class.
|
||||
/// </summary>
|
||||
public NoContentRoutes(
|
||||
IOptions<GlobalSettings> globalSettings,
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
IRuntimeState runtimeState)
|
||||
{
|
||||
_runtimeState = runtimeState;
|
||||
_umbracoPathSegment = globalSettings.Value.GetUmbracoMvcArea(hostingEnvironment);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CreateRoutes(IEndpointRouteBuilder endpoints)
|
||||
{
|
||||
switch (_runtimeState.Level)
|
||||
{
|
||||
case RuntimeLevel.Install:
|
||||
break;
|
||||
case RuntimeLevel.Upgrade:
|
||||
break;
|
||||
case RuntimeLevel.Run:
|
||||
|
||||
// TODO: I don't really think this is working AFAIK the code has just been migrated but it's not really enabled
|
||||
// yet. Our route handler needs to be aware that there is no content and redirect there. Though, this could all be
|
||||
// managed directly in UmbracoRouteValueTransformer. Else it could actually do a 'redirect' but that would need to be
|
||||
// an internal rewrite.
|
||||
endpoints.MapControllerRoute(
|
||||
Constants.Web.NoContentRouteName, // named consistently
|
||||
_umbracoPathSegment + "/UmbNoContent",
|
||||
new { controller = "RenderNoContent", action = "Index" });
|
||||
break;
|
||||
case RuntimeLevel.BootFailed:
|
||||
case RuntimeLevel.Unknown:
|
||||
case RuntimeLevel.Boot:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,14 +93,19 @@ namespace Umbraco.Web.Website.Routing
|
||||
return values;
|
||||
}
|
||||
|
||||
bool routed = RouteRequest(_umbracoContextAccessor.UmbracoContext, out IPublishedRequest publishedRequest);
|
||||
if (!routed)
|
||||
// Check if there is no existing content and return the no content controller
|
||||
if (!_umbracoContextAccessor.UmbracoContext.Content.HasContent())
|
||||
{
|
||||
return values;
|
||||
// TODO: Deal with it not being routable, perhaps this should be an enum result?
|
||||
values["controller"] = ControllerExtensions.GetControllerName<RenderNoContentController>();
|
||||
values["action"] = nameof(RenderNoContentController.Index);
|
||||
|
||||
return await Task.FromResult(values);
|
||||
}
|
||||
|
||||
RouteRequest(_umbracoContextAccessor.UmbracoContext, out IPublishedRequest publishedRequest);
|
||||
|
||||
UmbracoRouteValues routeDef = GetUmbracoRouteDefinition(httpContext, values, publishedRequest);
|
||||
|
||||
values["controller"] = routeDef.ControllerName;
|
||||
if (string.IsNullOrWhiteSpace(routeDef.ActionName) == false)
|
||||
{
|
||||
@@ -134,7 +139,6 @@ namespace Umbraco.Web.Website.Routing
|
||||
var defaultControllerName = ControllerExtensions.GetControllerName(defaultControllerType);
|
||||
|
||||
string customActionName = null;
|
||||
var customControllerName = request.PublishedContent.ContentType.Alias; // never null
|
||||
|
||||
// check that a template is defined), if it doesn't and there is a hijacked route it will just route
|
||||
// to the index Action
|
||||
@@ -143,17 +147,31 @@ namespace Umbraco.Web.Website.Routing
|
||||
// the template Alias should always be already saved with a safe name.
|
||||
// if there are hyphens in the name and there is a hijacked route, then the Action will need to be attributed
|
||||
// with the action name attribute.
|
||||
customActionName = request.GetTemplateAlias().Split('.')[0].ToSafeAlias(_shortStringHelper);
|
||||
customActionName = request.GetTemplateAlias()?.Split('.')[0].ToSafeAlias(_shortStringHelper);
|
||||
}
|
||||
|
||||
// creates the default route definition which maps to the 'UmbracoController' controller
|
||||
var def = new UmbracoRouteValues(
|
||||
request.PublishedContent,
|
||||
request,
|
||||
defaultControllerName,
|
||||
defaultControllerType,
|
||||
templateName: customActionName);
|
||||
|
||||
IReadOnlyList<ControllerActionDescriptor> candidates = FindControllerCandidates(customControllerName, customActionName, def.ActionName);
|
||||
var customControllerName = request.PublishedContent?.ContentType.Alias;
|
||||
if (customControllerName != null)
|
||||
{
|
||||
def = DetermineHijackedRoute(def, customControllerName, customActionName, request);
|
||||
}
|
||||
|
||||
// store the route definition
|
||||
values.TryAdd(Constants.Web.UmbracoRouteDefinitionDataToken, def);
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
private UmbracoRouteValues DetermineHijackedRoute(UmbracoRouteValues routeValues, string customControllerName, string customActionName, IPublishedRequest request)
|
||||
{
|
||||
IReadOnlyList<ControllerActionDescriptor> candidates = FindControllerCandidates(customControllerName, customActionName, routeValues.ActionName);
|
||||
|
||||
// check if there's a custom controller assigned, base on the document type alias.
|
||||
var customControllerCandidates = candidates.Where(x => x.ControllerName.InvariantEquals(customControllerName)).ToList();
|
||||
@@ -170,11 +188,12 @@ namespace Umbraco.Web.Website.Routing
|
||||
// now check if the custom action matches
|
||||
var customActionExists = customActionName != null && customControllerCandidates.Any(x => x.ActionName.InvariantEquals(customActionName));
|
||||
|
||||
def = new UmbracoRouteValues(
|
||||
request.PublishedContent,
|
||||
// it's a hijacked route with a custom controller, so return the the values
|
||||
return new UmbracoRouteValues(
|
||||
request,
|
||||
controllerDescriptor.ControllerName,
|
||||
controllerDescriptor.ControllerTypeInfo,
|
||||
customActionExists ? customActionName : def.ActionName,
|
||||
customActionExists ? customActionName : routeValues.ActionName,
|
||||
customActionName,
|
||||
true); // Hijacked = true
|
||||
}
|
||||
@@ -192,10 +211,7 @@ namespace Umbraco.Web.Website.Routing
|
||||
}
|
||||
}
|
||||
|
||||
// store the route definition
|
||||
values.TryAdd(Constants.Web.UmbracoRouteDefinitionDataToken, def);
|
||||
|
||||
return def;
|
||||
return routeValues;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -228,7 +244,7 @@ namespace Umbraco.Web.Website.Routing
|
||||
// Maybe could be a one-time Set method instead?
|
||||
publishedRequest = umbracoContext.PublishedRequest = _publishedRouter.RouteRequest(requestBuilder);
|
||||
|
||||
return publishedRequest.Success() && publishedRequest.HasPublishedContent();
|
||||
return publishedRequest.Success();
|
||||
|
||||
// // HandleHttpResponseStatus returns a value indicating that the request should
|
||||
// // not be processed any further, eg because it has been redirect. then, exit.
|
||||
|
||||
@@ -284,19 +284,22 @@ namespace Umbraco.Web.Mvc
|
||||
// missing template, so we're in a 404 here
|
||||
// so the content, if any, is a custom 404 page of some sort
|
||||
|
||||
if (request.HasPublishedContent() == false)
|
||||
{
|
||||
// means the builder could not find a proper document to handle 404
|
||||
return new PublishedContentNotFoundHandler();
|
||||
}
|
||||
|
||||
if (request.HasTemplate() == false)
|
||||
{
|
||||
// means the engine could find a proper document, but the document has no template
|
||||
// at that point there isn't much we can do and there is no point returning
|
||||
// to Mvc since Mvc can't do much
|
||||
return new PublishedContentNotFoundHandler("In addition, no template exists to render the custom 404.");
|
||||
}
|
||||
// TODO: Handle this differently in netcore....
|
||||
|
||||
//if (request.HasPublishedContent() == false)
|
||||
//{
|
||||
// // means the builder could not find a proper document to handle 404
|
||||
// return new PublishedContentNotFoundHandler();
|
||||
//}
|
||||
|
||||
//if (request.HasTemplate() == false)
|
||||
//{
|
||||
// // means the engine could find a proper document, but the document has no template
|
||||
// // at that point there isn't much we can do and there is no point returning
|
||||
// // to Mvc since Mvc can't do much
|
||||
// return new PublishedContentNotFoundHandler("In addition, no template exists to render the custom 404.");
|
||||
//}
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -318,6 +321,7 @@ namespace Umbraco.Web.Mvc
|
||||
return HandlePostedValues(requestContext, postedInfo);
|
||||
}
|
||||
|
||||
// TODO: Surely this check is part of the PublishedRouter?
|
||||
|
||||
// Here we need to check if there is no hijacked route and no template assigned,
|
||||
// if this is the case we want to return a blank page, but we'll leave that up to the NoTemplateHandler.
|
||||
@@ -326,13 +330,14 @@ namespace Umbraco.Web.Mvc
|
||||
if (request.HasTemplate() == false && Features.Disabled.DisableTemplates == false && routeDef.HasHijackedRoute == false)
|
||||
{
|
||||
|
||||
// TODO: Handle this differently
|
||||
// TODO: Handle this differently in netcore....
|
||||
|
||||
// request.UpdateToNotFound(); // request will go 404
|
||||
|
||||
// HandleHttpResponseStatus returns a value indicating that the request should
|
||||
// not be processed any further, eg because it has been redirect. then, exit.
|
||||
if (UmbracoModule.HandleHttpResponseStatus(requestContext.HttpContext, request, Current.Logger))
|
||||
return null;
|
||||
//if (UmbracoModule.HandleHttpResponseStatus(requestContext.HttpContext, request, Current.Logger))
|
||||
// return null;
|
||||
|
||||
var handler = GetHandlerOnMissingTemplate(request);
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
using System.Web;
|
||||
using Umbraco.Web.Composing;
|
||||
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets executed when no document can be found in Umbraco
|
||||
/// </summary>
|
||||
internal class PublishedContentNotFoundHandler : IHttpHandler
|
||||
{
|
||||
private readonly string _message;
|
||||
|
||||
public PublishedContentNotFoundHandler()
|
||||
{ }
|
||||
|
||||
public PublishedContentNotFoundHandler(string message)
|
||||
{
|
||||
_message = message;
|
||||
}
|
||||
|
||||
public void ProcessRequest(HttpContext context)
|
||||
{
|
||||
WriteOutput(context);
|
||||
}
|
||||
|
||||
internal void WriteOutput(HttpContext context)
|
||||
{
|
||||
var response = context.Response;
|
||||
|
||||
response.Clear();
|
||||
|
||||
var frequest = Current.UmbracoContext.PublishedRequest;
|
||||
var reason = "Cannot render the page at URL '{0}'.";
|
||||
if (frequest.HasPublishedContent() == false)
|
||||
reason = "No umbraco document matches the URL '{0}'.";
|
||||
else if (frequest.HasTemplate() == false)
|
||||
reason = "No template exists to render the document at URL '{0}'.";
|
||||
|
||||
response.Write("<html><body><h1>Page not found</h1>");
|
||||
response.Write("<h2>");
|
||||
response.Write(string.Format(reason, HttpUtility.HtmlEncode(Current.UmbracoContext.OriginalRequestUrl.PathAndQuery)));
|
||||
response.Write("</h2>");
|
||||
if (string.IsNullOrWhiteSpace(_message) == false)
|
||||
response.Write("<p>" + _message + "</p>");
|
||||
response.Write("<p>This page can be replaced with a custom 404. Check the documentation for \"custom 404\".</p>");
|
||||
response.Write("<p style=\"border-top: 1px solid #ccc; padding-top: 10px\"><small>This page is intentionally left ugly ;-)</small></p>");
|
||||
response.Write("</body></html>");
|
||||
}
|
||||
|
||||
public bool IsReusable => false;
|
||||
}
|
||||
}
|
||||
@@ -233,7 +233,6 @@
|
||||
<Compile Include="RouteCollectionExtensions.cs" />
|
||||
<Compile Include="UmbracoHelper.cs" />
|
||||
<Compile Include="Mvc\ViewDataContainerExtensions.cs" />
|
||||
<Compile Include="Routing\PublishedContentNotFoundHandler.cs" />
|
||||
<Compile Include="Mvc\RenderActionInvoker.cs" />
|
||||
<Compile Include="Mvc\RenderRouteHandler.cs" />
|
||||
<Compile Include="Mvc\RouteDefinition.cs" />
|
||||
|
||||
@@ -138,15 +138,15 @@ namespace Umbraco.Web
|
||||
var requestBuilder = _publishedRouter.CreateRequest(umbracoContext.CleanedUmbracoUrl);
|
||||
var request = umbracoContext.PublishedRequest = _publishedRouter.RouteRequest(requestBuilder);
|
||||
|
||||
// NOTE: This has been ported to netcore
|
||||
// HandleHttpResponseStatus returns a value indicating that the request should
|
||||
// not be processed any further, eg because it has been redirect. then, exit.
|
||||
if (UmbracoModule.HandleHttpResponseStatus(httpContext, request, _logger))
|
||||
return;
|
||||
|
||||
if (request.HasPublishedContent() == false)
|
||||
httpContext.RemapHandler(new PublishedContentNotFoundHandler());
|
||||
else
|
||||
RewriteToUmbracoHandler(httpContext, request);
|
||||
//if (UmbracoModule.HandleHttpResponseStatus(httpContext, request, _logger))
|
||||
// return;
|
||||
//if (request.HasPublishedContent() == false)
|
||||
// httpContext.RemapHandler(new PublishedContentNotFoundHandler());
|
||||
//else
|
||||
// RewriteToUmbracoHandler(httpContext, request);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -257,40 +257,6 @@ namespace Umbraco.Web
|
||||
urlRouting.PostResolveRequestCache(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rewrites to the Umbraco handler - we always send the request via our MVC rendering engine, this will deal with
|
||||
/// requests destined for webforms.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="pcr"> </param>
|
||||
private void RewriteToUmbracoHandler(HttpContextBase context, IPublishedRequest pcr)
|
||||
{
|
||||
// NOTE: we do not want to use TransferRequest even though many docs say it is better with IIS7, turns out this is
|
||||
// not what we need. The purpose of TransferRequest is to ensure that .net processes all of the rules for the newly
|
||||
// rewritten URL, but this is not what we want!
|
||||
// read: http://forums.iis.net/t/1146511.aspx
|
||||
|
||||
var query = pcr.Uri.Query.TrimStart('?');
|
||||
|
||||
// GlobalSettings.Path has already been through IOHelper.ResolveUrl() so it begins with / and vdir (if any)
|
||||
var rewritePath = _globalSettings.GetBackOfficePath(_hostingEnvironment).TrimEnd('/') + "/RenderMvc";
|
||||
// rewrite the path to the path of the handler (i.e. /umbraco/RenderMvc)
|
||||
context.RewritePath(rewritePath, "", query, false);
|
||||
|
||||
//if it is MVC we need to do something special, we are not using TransferRequest as this will
|
||||
//require us to rewrite the path with query strings and then re-parse the query strings, this would
|
||||
//also mean that we need to handle IIS 7 vs pre-IIS 7 differently. Instead we are just going to create
|
||||
//an instance of the UrlRoutingModule and call it's PostResolveRequestCache method. This does:
|
||||
// * Looks up the route based on the new rewritten URL
|
||||
// * Creates the RequestContext with all route parameters and then executes the correct handler that matches the route
|
||||
//we also cannot re-create this functionality because the setter for the HttpContext.Request.RequestContext is internal
|
||||
//so really, this is pretty much the only way without using Server.TransferRequest and if we did that, we'd have to rethink
|
||||
//a bunch of things!
|
||||
var urlRouting = new UrlRoutingModule();
|
||||
urlRouting.PostResolveRequestCache(context);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -41,65 +41,5 @@ namespace Umbraco.Web
|
||||
{
|
||||
EndRequest?.Invoke(sender, args);
|
||||
}
|
||||
|
||||
// returns a value indicating whether redirection took place and the request has
|
||||
// been completed - because we don't want to Response.End() here to terminate
|
||||
// everything properly.
|
||||
internal static bool HandleHttpResponseStatus(HttpContextBase context, IPublishedRequest pcr, ILogger logger)
|
||||
{
|
||||
var end = false;
|
||||
var response = context.Response;
|
||||
|
||||
logger.LogDebug("Response status: Redirect={Redirect}, Is404={Is404}, StatusCode={ResponseStatusCode}",
|
||||
pcr.IsRedirect() ? (pcr.IsRedirectPermanent() ? "permanent" : "redirect") : "none",
|
||||
pcr.Is404() ? "true" : "false",
|
||||
pcr.ResponseStatusCode);
|
||||
|
||||
if(pcr.CacheabilityNoCache)
|
||||
response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);
|
||||
|
||||
foreach (var cacheExtension in pcr.CacheExtensions)
|
||||
response.Cache.AppendCacheExtension(cacheExtension);
|
||||
|
||||
foreach (var header in pcr.Headers)
|
||||
response.AppendHeader(header.Key, header.Value);
|
||||
|
||||
if (pcr.IsRedirect())
|
||||
{
|
||||
if (pcr.IsRedirectPermanent())
|
||||
response.RedirectPermanent(pcr.RedirectUrl, false); // do not end response
|
||||
else
|
||||
response.Redirect(pcr.RedirectUrl, false); // do not end response
|
||||
end = true;
|
||||
}
|
||||
else if (pcr.Is404())
|
||||
{
|
||||
response.StatusCode = 404;
|
||||
response.TrySkipIisCustomErrors = /*Current.Configs.WebRouting().TrySkipIisCustomErrors; TODO introduce from config*/ false;
|
||||
|
||||
if (response.TrySkipIisCustomErrors == false)
|
||||
logger.LogWarning("Status code is 404 yet TrySkipIisCustomErrors is false - IIS will take over.");
|
||||
}
|
||||
|
||||
if (pcr.ResponseStatusCode > 0)
|
||||
{
|
||||
// set status code -- even for redirects
|
||||
response.StatusCode = pcr.ResponseStatusCode;
|
||||
response.StatusDescription = pcr.ResponseStatusDescription;
|
||||
}
|
||||
//if (pcr.IsRedirect)
|
||||
// response.End(); // end response -- kills the thread and does not return!
|
||||
|
||||
if (pcr.IsRedirect() == false) return end;
|
||||
|
||||
response.Flush();
|
||||
// bypass everything and directly execute EndRequest event -- but returns
|
||||
context.ApplicationInstance.CompleteRequest();
|
||||
// though some say that .CompleteRequest() does not properly shutdown the response
|
||||
// and the request will hang until the whole code has run... would need to test?
|
||||
logger.LogDebug("Response status: redirecting, complete request now.");
|
||||
|
||||
return end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user