Пример #1
0
        /// <summary>
        /// Tries to find the document matching the request, by running the IPublishedContentFinder instances.
        /// </summary>
        /// <exception cref="InvalidOperationException">There is no finder collection.</exception>
        internal bool FindPublishedContent(IPublishedRequestBuilder request)
        {
            const string tracePrefix = "FindPublishedContent: ";

            // look for the document
            // the first successful finder, if any, will set this.PublishedContent, and may also set this.Template
            // some finders may implement caching
            using (_profilingLogger.DebugDuration <PublishedRouter>(
                       $"{tracePrefix}Begin finders",
                       $"{tracePrefix}End finders"))
            {
                // iterate but return on first one that finds it
                var found = _contentFinders.Any(finder =>
                {
                    _logger.LogDebug("Finder {ContentFinderType}", finder.GetType().FullName);
                    return(finder.TryFindContent(request));
                });

                _logger.LogDebug(
                    "Found? {Found}, Content: {PublishedContentId}, Template: {TemplateAlias}, Domain: {Domain}, Culture: {Culture}, StatusCode: {StatusCode}",
                    found,
                    request.HasPublishedContent() ? request.PublishedContent.Id : "NULL",
                    request.HasTemplate() ? request.Template?.Alias : "NULL",
                    request.HasDomain() ? request.Domain.ToString() : "NULL",
                    request.Culture ?? "NULL",
                    request.ResponseStatusCode);

                return(found);
            }
        }
Пример #2
0
    /// <summary>
    ///     Tries to find the document matching the request, by running the IPublishedContentFinder instances.
    /// </summary>
    /// <exception cref="InvalidOperationException">There is no finder collection.</exception>
    internal async Task <bool> FindPublishedContent(IPublishedRequestBuilder request)
    {
        const string tracePrefix = "FindPublishedContent: ";

        // look for the document
        // the first successful finder, if any, will set this.PublishedContent, and may also set this.Template
        // some finders may implement caching
        DisposableTimer?profilingScope = null;

        try
        {
            if (_logger.IsEnabled(LogLevel.Debug))
            {
                profilingScope = _profilingLogger.DebugDuration <PublishedRouter>(
                    $"{tracePrefix}Begin finders",
                    $"{tracePrefix}End finders");
            }

            // iterate but return on first one that finds it
            var found = false;
            foreach (IContentFinder contentFinder in _contentFinders)
            {
                if (_logger.IsEnabled(LogLevel.Debug))
                {
                    _logger.LogDebug("Finder {ContentFinderType}", contentFinder.GetType().FullName);
                }

                found = await contentFinder.TryFindContent(request);

                if (found)
                {
                    break;
                }
            }

            if (_logger.IsEnabled(LogLevel.Debug))
            {
                _logger.LogDebug(
                    "Found? {Found}, Content: {PublishedContentId}, Template: {TemplateAlias}, Domain: {Domain}, Culture: {Culture}, StatusCode: {StatusCode}",
                    found,
                    request.HasPublishedContent() ? request.PublishedContent?.Id : "NULL",
                    request.HasTemplate() ? request.Template?.Alias : "NULL",
                    request.HasDomain() ? request.Domain?.ToString() : "NULL",
                    request.Culture ?? "NULL",
                    request.ResponseStatusCode);
            }

            return(found);
        }
        finally
        {
            profilingScope?.Dispose();
        }
    }
Пример #3
0
    /// <summary>
    ///     Finds a template for the current node, if any.
    /// </summary>
    /// <param name="request">The request builder.</param>
    /// <param name="contentFoundByFinders">
    ///     If the content was found by the finders, before anything such as 404, redirect...
    ///     took place.
    /// </param>
    private void FindTemplate(IPublishedRequestBuilder request, bool contentFoundByFinders)
    {
        // TODO: We've removed the event, might need to re-add?
        // NOTE: at the moment there is only 1 way to find a template, and then ppl must
        // use the Prepared event to change the template if they wish. Should we also
        // implement an ITemplateFinder logic?
        if (request.PublishedContent == null)
        {
            request.SetTemplate(null);
            return;
        }

        // read the alternate template alias, from querystring, form, cookie or server vars,
        // only if the published content is the initial once, else the alternate template
        // does not apply
        // + optionally, apply the alternate template on internal redirects
        var useAltTemplate = contentFoundByFinders ||
                             (_webRoutingSettings.InternalRedirectPreservesTemplate && request.IsInternalRedirect);

        var altTemplate = useAltTemplate
            ? _requestAccessor.GetRequestValue(Constants.Conventions.Url.AltTemplate)
            : null;

        if (string.IsNullOrWhiteSpace(altTemplate))
        {
            // we don't have an alternate template specified. use the current one if there's one already,
            // which can happen if a content lookup also set the template (LookupByNiceUrlAndTemplate...),
            // else lookup the template id on the document then lookup the template with that id.
            if (request.HasTemplate())
            {
                if (_logger.IsEnabled(LogLevel.Debug))
                {
                    _logger.LogDebug("FindTemplate: Has a template already, and no alternate template.");
                }

                return;
            }

            // TODO: We need to limit altTemplate to only allow templates that are assigned to the current document type!
            // if the template isn't assigned to the document type we should log a warning and return 404
            var       templateId = request.PublishedContent.TemplateId;
            ITemplate?template   = GetTemplate(templateId);
            request.SetTemplate(template);
            if (template != null)
            {
                if (_logger.IsEnabled(LogLevel.Debug))
                {
                    _logger.LogDebug(
                        "FindTemplate: Running with template id={TemplateId} alias={TemplateAlias}",
                        template.Id,
                        template.Alias);
                }
            }
            else
            {
                _logger.LogWarning("FindTemplate: Could not find template with id {TemplateId}", templateId);
            }
        }
        else
        {
            // we have an alternate template specified. lookup the template with that alias
            // this means the we override any template that a content lookup might have set
            // so /path/to/page/template1?altTemplate=template2 will use template2

            // ignore if the alias does not match - just trace
            if (request.HasTemplate())
            {
                if (_logger.IsEnabled(LogLevel.Debug))
                {
                    _logger.LogDebug("FindTemplate: Has a template already, but also an alternative template.");
                }
            }

            if (_logger.IsEnabled(LogLevel.Debug))
            {
                _logger.LogDebug("FindTemplate: Look for alternative template alias={AltTemplate}", altTemplate);
            }

            // IsAllowedTemplate deals both with DisableAlternativeTemplates and ValidateAlternativeTemplates settings
            if (request.PublishedContent.IsAllowedTemplate(
                    _fileService,
                    _contentTypeService,
                    _webRoutingSettings.DisableAlternativeTemplates,
                    _webRoutingSettings.ValidateAlternativeTemplates,
                    altTemplate))
            {
                // allowed, use
                ITemplate?template = _fileService.GetTemplate(altTemplate);

                if (template != null)
                {
                    request.SetTemplate(template);
                    if (_logger.IsEnabled(LogLevel.Debug))
                    {
                        _logger.LogDebug(
                            "FindTemplate: Got alternative template id={TemplateId} alias={TemplateAlias}",
                            template.Id,
                            template.Alias);
                    }
                }
                else
                {
                    if (_logger.IsEnabled(LogLevel.Debug))
                    {
                        _logger.LogDebug(
                            "FindTemplate: The alternative template with alias={AltTemplate} does not exist, ignoring.",
                            altTemplate);
                    }
                }
            }
            else
            {
                _logger.LogWarning(
                    "FindTemplate: Alternative template {TemplateAlias} is not allowed on node {NodeId}, ignoring.",
                    altTemplate,
                    request.PublishedContent.Id);

                // no allowed, back to default
                var       templateId = request.PublishedContent.TemplateId;
                ITemplate?template   = GetTemplate(templateId);
                request.SetTemplate(template);
                if (_logger.IsEnabled(LogLevel.Debug))
                {
                    _logger.LogDebug(
                        "FindTemplate: Running with template id={TemplateId} alias={TemplateAlias}",
                        template?.Id,
                        template?.Alias);
                }
            }
        }

        if (!request.HasTemplate())
        {
            if (_logger.IsEnabled(LogLevel.Debug))
            {
                _logger.LogDebug("FindTemplate: No template was found.");
            }

            // initial idea was: if we're not already 404 and UmbracoSettings.HandleMissingTemplateAs404 is true
            // then reset _pcr.Document to null to force a 404.
            //
            // but: because we want to let MVC hijack routes even though no template is defined, we decide that
            // a missing template is OK but the request will then be forwarded to MVC, which will need to take
            // care of everything.
            //
            // so, don't set _pcr.Document to null here
        }
    }
    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);
        }
    }