Esempio n. 1
0
 /// <summary>
 /// Gets a value indicating whether the content request has a content.
 /// </summary>
 public static bool HasPublishedContent(this IPublishedRequest publishedRequest) => publishedRequest.PublishedContent != null;
Esempio n. 2
0
    /// <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);
    }
Esempio n. 3
0
 /// <summary>
 /// Gets a value indicating whether the request was successfully routed
 /// </summary>
 public static bool Success(this IPublishedRequest publishedRequest)
 => !publishedRequest.IsRedirect() && publishedRequest.HasPublishedContent();
Esempio n. 4
0
        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);
        }
    }
Esempio n. 6
0
 /// <summary>
 /// Gets a value indicating whether the redirect is permanent.
 /// </summary>
 public static bool IsRedirectPermanent(this IPublishedRequest publishedRequest) => publishedRequest.ResponseStatusCode == (int)HttpStatusCode.Moved;
Esempio n. 7
0
 /// <summary>
 /// Gets a value indicating whether the content request has a domain.
 /// </summary>
 public static bool HasDomain(this IPublishedRequest publishedRequest) => publishedRequest.Domain != null;
Esempio n. 8
0
 /// <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;
Esempio n. 9
0
 /// <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;
Esempio n. 10
0
 /// <summary>
 /// Gets a value indicating whether the content request has a template.
 /// </summary>
 public static bool HasTemplate(this IPublishedRequest publishedRequest) => publishedRequest.Template != null;
Esempio n. 11
0
        /// <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.");
            }
        }