/// <summary> /// Looks for wildcard domains in the path and updates <c>Culture</c> accordingly. /// </summary> internal void HandleWildcardDomains(IPublishedRequestBuilder request) { const string tracePrefix = "HandleWildcardDomains: "; if (request.PublishedContent == null) { return; } var nodePath = request.PublishedContent.Path; _logger.LogDebug("{TracePrefix}Path={NodePath}", tracePrefix, nodePath); var rootNodeId = request.Domain != null ? request.Domain.ContentId : (int?)null; var umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext(); Domain domain = DomainUtilities.FindWildcardDomainInPath(umbracoContext.PublishedSnapshot.Domains.GetAll(true), nodePath, rootNodeId); // always has a contentId and a culture if (domain != null) { request.SetCulture(domain.Culture); _logger.LogDebug("{TracePrefix}Got domain on node {DomainContentId}, set culture to {CultureName}", tracePrefix, domain.ContentId, request.Culture); } else { _logger.LogDebug("{TracePrefix}No match.", tracePrefix); } }
/// <summary> /// Tries to find and assign an Umbraco document to a <c>PublishedRequest</c>. /// </summary> /// <param name="frequest">The <c>PublishedRequest</c>.</param> /// <returns>A value indicating whether an Umbraco document was found and assigned.</returns> public bool TryFindContent(IPublishedRequestBuilder frequest) { if (!_umbracoContextAccessor.TryGetUmbracoContext(out var umbracoContext)) { return(false); } if (umbracoContext == null || (umbracoContext != null && umbracoContext.InPreviewMode == false && _webRoutingSettings.DisableFindContentByIdPath)) { return(false); } IPublishedContent node = null; var path = frequest.AbsolutePathDecoded; var nodeId = -1; // no id if "/" if (path != "/") { var noSlashPath = path.Substring(1); if (int.TryParse(noSlashPath, NumberStyles.Integer, CultureInfo.InvariantCulture, out nodeId) == false) { nodeId = -1; } if (nodeId > 0) { _logger.LogDebug("Id={NodeId}", nodeId); node = umbracoContext.Content.GetById(nodeId); if (node != null) { var cultureFromQuerystring = _requestAccessor.GetQueryStringValue("culture"); // if we have a node, check if we have a culture in the query string if (!string.IsNullOrEmpty(cultureFromQuerystring)) { // we're assuming it will match a culture, if an invalid one is passed in, an exception will throw (there is no TryGetCultureInfo method), i think this is ok though frequest.SetCulture(cultureFromQuerystring); } frequest.SetPublishedContent(node); _logger.LogDebug("Found node with id={PublishedContentId}", node.Id); } else { nodeId = -1; // trigger message below } } } if (nodeId == -1) { _logger.LogDebug("Not a node id"); } return(node != null); }
/// <summary> /// Finds the site root (if any) matching the http request, and updates the PublishedRequest accordingly. /// </summary> /// <returns>A value indicating whether a domain was found.</returns> internal bool FindDomain(IPublishedRequestBuilder request) { const string tracePrefix = "FindDomain: "; // note - we are not handling schemes nor ports here. if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug("{TracePrefix}Uri={RequestUri}", tracePrefix, request.Uri); } IUmbracoContext umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext(); IDomainCache? domainsCache = umbracoContext.PublishedSnapshot.Domains; var domains = domainsCache?.GetAll(false).ToList(); // determines whether a domain corresponds to a published document, since some // domains may exist but on a document that has been unpublished - as a whole - or // that is not published for the domain's culture - in which case the domain does // not apply bool IsPublishedContentDomain(Domain domain) { // just get it from content cache - optimize there, not here IPublishedContent?domainDocument = umbracoContext.PublishedSnapshot.Content?.GetById(domain.ContentId); // not published - at all if (domainDocument == null) { return(false); } // invariant - always published if (!domainDocument.ContentType.VariesByCulture()) { return(true); } // variant, ensure that the culture corresponding to the domain's language is published return(domain.Culture is not null && domainDocument.Cultures.ContainsKey(domain.Culture)); } domains = domains?.Where(IsPublishedContentDomain).ToList(); var defaultCulture = domainsCache?.DefaultCulture; // try to find a domain matching the current request DomainAndUri?domainAndUri = DomainUtilities.SelectDomain(domains, request.Uri, defaultCulture: defaultCulture); // handle domain - always has a contentId and a culture if (domainAndUri != null) { // matching an existing domain if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug( "{TracePrefix}Matches domain={Domain}, rootId={RootContentId}, culture={Culture}", tracePrefix, domainAndUri.Name, domainAndUri.ContentId, domainAndUri.Culture); } request.SetDomain(domainAndUri); // canonical? not implemented at the moment // if (...) // { // _pcr.RedirectUrl = "..."; // return true; // } } else { // not matching any existing domain if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug("{TracePrefix}Matches no domain", tracePrefix); } request.SetCulture(defaultCulture ?? CultureInfo.CurrentUICulture.Name); } if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug("{TracePrefix}Culture={CultureName}", tracePrefix, request.Culture); } return(request.Domain != null); }
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); } }