/// <summary> /// Gets a value indicating whether the content request has a content. /// </summary> public static bool HasPublishedContent(this IPublishedRequest publishedRequest) => publishedRequest.PublishedContent != null;
/// <inheritdoc /> public override async ValueTask <RouteValueDictionary> TransformAsync( HttpContext httpContext, RouteValueDictionary values) { // If we aren't running, then we have nothing to route if (_runtime.Level != RuntimeLevel.Run) { return(null !); } // will be null for any client side requests like JS, etc... if (!_umbracoContextAccessor.TryGetUmbracoContext(out IUmbracoContext? umbracoContext)) { return(null !); } if (!_routableDocumentFilter.IsDocumentRequest(httpContext.Request.Path)) { return(null !); } // Don't execute if there are already UmbracoRouteValues assigned. // This can occur if someone else is dynamically routing and in which case we don't want to overwrite // the routing work being done there. UmbracoRouteValues?umbracoRouteValues = httpContext.Features.Get <UmbracoRouteValues>(); if (umbracoRouteValues != null) { return(null !); } // Check if there is no existing content and return the no content controller if (!umbracoContext.Content?.HasContent() ?? false) { return(new RouteValueDictionary { [ControllerToken] = ControllerExtensions.GetControllerName <RenderNoContentController>(), [ActionToken] = nameof(RenderNoContentController.Index), }); } IPublishedRequest publishedRequest = await RouteRequestAsync(umbracoContext); umbracoRouteValues = await _routeValuesFactory.CreateAsync(httpContext, publishedRequest); // now we need to do some public access checks umbracoRouteValues = await _publicAccessRequestHandler.RewriteForPublishedContentAccessAsync(httpContext, umbracoRouteValues); // 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) { return(HandlePostedValues(postedInfo, httpContext)); } UmbracoRouteResult?routeResult = umbracoRouteValues?.PublishedRequest.GetRouteResult(); if (!routeResult.HasValue || routeResult == UmbracoRouteResult.NotFound) { // No content was found, not by any registered 404 handlers and // not by the IContentLastChanceFinder. In this case we want to return // our default 404 page but we cannot return route values now because // it's possible that a developer is handling dynamic routes too. // Our 404 page will be handled with the NotFoundSelectorPolicy return(null !); } // See https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.routing.dynamicroutevaluetransformer.transformasync?view=aspnetcore-5.0#Microsoft_AspNetCore_Mvc_Routing_DynamicRouteValueTransformer_TransformAsync_Microsoft_AspNetCore_Http_HttpContext_Microsoft_AspNetCore_Routing_RouteValueDictionary_ // We should apparenlty not be modified these values. // So we create new ones. var newValues = new RouteValueDictionary { [ControllerToken] = umbracoRouteValues?.ControllerName }; if (string.IsNullOrWhiteSpace(umbracoRouteValues?.ActionName) == false) { newValues[ActionToken] = umbracoRouteValues.ActionName; } return(newValues); }
/// <summary> /// Gets a value indicating whether the request was successfully routed /// </summary> public static bool Success(this IPublishedRequest publishedRequest) => !publishedRequest.IsRedirect() && publishedRequest.HasPublishedContent();
private static async Task <Attempt <UrlInfo> > DetectCollisionAsync(ILogger logger, IContent content, string url, string culture, IUmbracoContext umbracoContext, IPublishedRouter publishedRouter, ILocalizedTextService textService, IVariationContextAccessor variationContextAccessor, UriUtility uriUtility) { // test for collisions on the 'main' URL var uri = new Uri(url.TrimEnd(Constants.CharArrays.ForwardSlash), UriKind.RelativeOrAbsolute); if (uri.IsAbsoluteUri == false) { uri = uri.MakeAbsolute(umbracoContext.CleanedUmbracoUrl); } uri = uriUtility.UriToUmbraco(uri); IPublishedRequestBuilder builder = await publishedRouter.CreateRequestAsync(uri); IPublishedRequest pcr = await publishedRouter.RouteRequestAsync(builder, new RouteRequestOptions(RouteDirection.Outbound)); if (!pcr.HasPublishedContent()) { var logMsg = nameof(DetectCollisionAsync) + " did not resolve a content item for original url: {Url}, translated to {TranslatedUrl} and culture: {Culture}"; if (pcr.IgnorePublishedContentCollisions) { logger.LogDebug(logMsg, url, uri, culture); } else { logger.LogDebug(logMsg, url, uri, culture); } var urlInfo = UrlInfo.Message(textService.Localize("content", "routeErrorCannotRoute"), culture); return(Attempt.Succeed(urlInfo)); } if (pcr.IgnorePublishedContentCollisions) { return(Attempt <UrlInfo> .Fail()); } if (pcr.PublishedContent.Id != content.Id) { IPublishedContent o = pcr.PublishedContent; var l = new List <string>(); while (o != null) { l.Add(o.Name(variationContextAccessor)); o = o.Parent; } l.Reverse(); var s = "/" + string.Join("/", l) + " (id=" + pcr.PublishedContent.Id + ")"; var urlInfo = UrlInfo.Message(textService.Localize("content", "routeError", new[] { s }), culture); return(Attempt.Succeed(urlInfo)); } // collisions with a different culture of the same content can never be routed. if (!culture.InvariantEquals(pcr.Culture)) { var urlInfo = UrlInfo.Message(textService.Localize("content", "routeErrorCannotRoute"), culture); return(Attempt.Succeed(urlInfo)); } // no collision return(Attempt <UrlInfo> .Fail()); }
public async Task RenderAsync(int pageId, int?altTemplateId, StringWriter writer) { if (writer == null) { throw new ArgumentNullException(nameof(writer)); } IUmbracoContext umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext(); // instantiate a request and process // important to use CleanedUmbracoUrl - lowercase path-only version of the current URL, though this isn't going to matter // terribly much for this implementation since we are just creating a doc content request to modify it's properties manually. IPublishedRequestBuilder requestBuilder = await _publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl); IPublishedContent?doc = umbracoContext.Content?.GetById(pageId); if (doc == null) { writer.Write("<!-- Could not render template for Id {0}, the document was not found -->", pageId); return; } // in some cases the UmbracoContext will not have a PublishedRequest assigned to it if we are not in the // execution of a front-end rendered page. In this case set the culture to the default. // set the culture to the same as is currently rendering if (umbracoContext.PublishedRequest == null) { ILanguage?defaultLanguage = _languageService.GetAllLanguages().FirstOrDefault(); requestBuilder.SetCulture(defaultLanguage == null ? CultureInfo.CurrentUICulture.Name : defaultLanguage.IsoCode); } else { requestBuilder.SetCulture(umbracoContext.PublishedRequest.Culture); } // set the doc that was found by id requestBuilder.SetPublishedContent(doc); // set the template, either based on the AltTemplate found or the standard template of the doc var templateId = _webRoutingSettings.DisableAlternativeTemplates || !altTemplateId.HasValue ? doc.TemplateId : altTemplateId.Value; if (templateId.HasValue) { requestBuilder.SetTemplate(_fileService.GetTemplate(templateId.Value)); } // if there is not template then exit if (requestBuilder.HasTemplate() == false) { if (altTemplateId.HasValue == false) { writer.Write( "<!-- Could not render template for Id {0}, the document's template was not found with id {0}-->", doc.TemplateId); } else { writer.Write( "<!-- Could not render template for Id {0}, the altTemplate was not found with id {0}-->", altTemplateId); } return; } // First, save all of the items locally that we know are used in the chain of execution, we'll need to restore these // after this page has rendered. SaveExistingItems(out IPublishedRequest? oldPublishedRequest); IPublishedRequest contentRequest = requestBuilder.Build(); try { // set the new items on context objects for this templates execution SetNewItemsOnContextObjects(contentRequest); // Render the template ExecuteTemplateRendering(writer, contentRequest); } finally { // restore items on context objects to continuing rendering the parent template RestoreItems(oldPublishedRequest); } }
/// <summary> /// Gets a value indicating whether the redirect is permanent. /// </summary> public static bool IsRedirectPermanent(this IPublishedRequest publishedRequest) => publishedRequest.ResponseStatusCode == (int)HttpStatusCode.Moved;
/// <summary> /// Gets a value indicating whether the content request has a domain. /// </summary> public static bool HasDomain(this IPublishedRequest publishedRequest) => publishedRequest.Domain != null;
/// <summary> /// Gets a value indicating whether the requested content could not be found. /// </summary> public static bool Is404(this IPublishedRequest publishedRequest) => publishedRequest.ResponseStatusCode == (int)HttpStatusCode.NotFound;
/// <summary> /// Gets the alias of the template to use to display the requested content. /// </summary> public static string?GetTemplateAlias(this IPublishedRequest publishedRequest) => publishedRequest.Template?.Alias;
/// <summary> /// Gets a value indicating whether the content request has a template. /// </summary> public static bool HasTemplate(this IPublishedRequest publishedRequest) => publishedRequest.Template != null;
/// <summary> /// Restores all items back to their context's to continue normal page rendering execution /// </summary> private void RestoreItems(IPublishedRequest oldPublishedRequest) { var umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext(); umbracoContext.PublishedRequest = oldPublishedRequest; }
private async Task <UmbracoRouteValues> SetPublishedContentAsOtherPageAsync(HttpContext httpContext, IPublishedRequest publishedRequest, int pageId) { if (pageId != publishedRequest.PublishedContent.Id) { var umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext(); IPublishedContent publishedContent = umbracoContext.PublishedSnapshot.Content.GetById(pageId); if (publishedContent == null) { throw new InvalidOperationException("No content found by id " + pageId); } IPublishedRequest reRouted = await _publishedRouter.UpdateRequestAsync(publishedRequest, publishedContent); // we need to change the content item that is getting rendered so we have to re-create UmbracoRouteValues. UmbracoRouteValues updatedRouteValues = await _umbracoRouteValuesFactory.CreateAsync(httpContext, reRouted); return(updatedRouteValues); } else { throw new InvalidOperationException("Public Access rule has a redirect node set to itself, nothing can be routed."); } }