public Uri GetPeerPageUrl(SPWeb web, Uri currentUrl, VariationLabelInfo label) { // Special case for application pages under /_layouts: // oftentimes, when on a _layouts page, the Httpcontext.Current.Request.Uri // (a typical input for this method) will give you a false URL (even if visiting a // sub-web's _layouts page, HttpContext will give you the root web's corresponding // _layouts page). if (currentUrl.AbsolutePath.StartsWith("/_layouts", StringComparison.OrdinalIgnoreCase)) { // Build an alternate currentUrl value that will be used at the end of the first catch block below... // and converted to use the proper peer variated web url (i.e. the peer variation sub-web // associated to current web might not have the same relative path vs. original language) string[] splitOnLayouts = currentUrl.ToString().Split(new string[] { "/_layouts" }, StringSplitOptions.None); currentUrl = new Uri(SPUtility.ConcatUrls(SPUtility.ConcatUrls(web.Url, "/_layouts"), splitOnLayouts[1])); } try { // Important: Use the server relative URL (absolute path) as the current URL parameter. // In the case where a load balancer is used, the server URL might be changed. // Omit this problem by using the server relative URL. var peerPageUri = new Uri(Variations.GetPeerUrl(web, currentUrl.AbsolutePath, label.Title), UriKind.Relative); // Special case for home page if (SPContext.Current.ListItem != null && web.RootFolder.WelcomePage == SPContext.Current.ListItem.Url) { var peerHomePageUrl = Regex.Replace(peerPageUri.OriginalString, @"\/Pages\/.*", string.Empty); peerPageUri = new Uri(peerHomePageUrl, UriKind.Relative); } return peerPageUri; } catch (ArgumentOutOfRangeException) { string webPeerServerRelativeUrl; // Keep query string (except source, and list,... and whichever other harmful-if-passed-on-variated-page-url argument) var queryCollection = HttpUtility.ParseQueryString(currentUrl.Query); queryCollection.Remove("Source"); queryCollection.Remove("List"); try { // Use a trick: use the current web's home page (welcome page on its root folder) to find the peer // web URL (i.e. the URL of the variated site which corresponds to the translated content - maybe with a // different relative path - of the current web) var currentWebWelcomePageUrl = SPUtility.ConcatUrls(web.Url, web.RootFolder.WelcomePage); var currentWebWelcomePageUrlRelative = new Uri(currentWebWelcomePageUrl, UriKind.Absolute).AbsolutePath; webPeerServerRelativeUrl = Variations.GetPeerUrl(web, currentWebWelcomePageUrlRelative, label.Title); // We heavily assume that all welcome pages lives in a Pages library here: webPeerServerRelativeUrl = webPeerServerRelativeUrl.Split(new[] { "/Pages" }, StringSplitOptions.None)[0]; webPeerServerRelativeUrl = webPeerServerRelativeUrl.EndsWith("/", StringComparison.OrdinalIgnoreCase) ? webPeerServerRelativeUrl : webPeerServerRelativeUrl + "/"; if (queryCollection["RootFolder"] != null) { // if we're successful, we're probably in a Pages library and we need the RootFolder // to get a replaced web URL as well var rootFolderParam = queryCollection["RootFolder"]; var currentServerWebRelativeUrl = web.RootFolder.ServerRelativeUrl; rootFolderParam = rootFolderParam.Replace(currentServerWebRelativeUrl, webPeerServerRelativeUrl); queryCollection["RootFolder"] = rootFolderParam; } // the logic below expects an absolute URL with domain etc. var baseSiteAbsoluteUrl = new Uri(web.Site.Url); webPeerServerRelativeUrl = new Uri(baseSiteAbsoluteUrl, new Uri(webPeerServerRelativeUrl, UriKind.Relative)).ToString(); } catch (ArgumentOutOfRangeException uglyNestedEx) { // default to the top web of the target variation hierarchy if all else fails (no peer of current // web welcome page found on target web) webPeerServerRelativeUrl = label.TopWebUrl + "/"; this.logger.Warn( "GetPeerUrl: Cannot find variation peer URL with web '{0}', url '{1}' and label '{2}'. Exception message: '{3}'.", web.Url, currentUrl.AbsolutePath, label.Title, uglyNestedEx.Message); } // Construct peer URL with path + query. var targetWebUrl = new Uri(webPeerServerRelativeUrl); var currentUrlSegmentsMinusTargetses = currentUrl.Segments.Skip(targetWebUrl.Segments.Length); var pathAndQuerySegments = new List<string>(targetWebUrl.Segments.Concat(currentUrlSegmentsMinusTargetses)); // If any query string, add to segments if (queryCollection.HasKeys()) { pathAndQuerySegments.Add(string.Format(CultureInfo.InvariantCulture, "?{0}", queryCollection)); } return new Uri(targetWebUrl, new Uri(string.Join(string.Empty, pathAndQuerySegments), UriKind.Relative)); } }
/// <summary> /// Get the peer url for a page represents a cross site publishing catalog item /// </summary> /// <param name="currentUrl">The current page url</param> /// <param name="label">The target label to resolve</param> /// <param name="associationKeyManagedPropertyName">The content association key search managed property name</param> /// <param name="associationKeyValue">The value of the content association key for the current item</param> /// <param name="languageManagedPropertyName">The language search managed property name</param> /// <param name="catalogNavigationTermManagedPropertyName">The navigation search managed property name used for the friendly url generation</param> /// <returns>The url of the peer page</returns> public Uri GetPeerCatalogItemUrl( Uri currentUrl, VariationLabelInfo label, string associationKeyManagedPropertyName, string associationKeyValue, string languageManagedPropertyName, string catalogNavigationTermManagedPropertyName) { ValidateProperties("GetPeerCatalogItemUrl", associationKeyManagedPropertyName, associationKeyValue, catalogNavigationTermManagedPropertyName); var url = new Uri(Variations.GetPeerUrl(SPContext.Current.Web, currentUrl.AbsolutePath, label.Title), UriKind.Relative); var searchResultSource = this.searchHelper.GetResultSourceByName(SPContext.Current.Site, LocalSharePointResultsSourceName, SearchObjectLevel.Ssa); var queryText = string.Format( CultureInfo.InvariantCulture, "{0}:{1} {2}:{3}", associationKeyManagedPropertyName, associationKeyValue, languageManagedPropertyName, label.Language); var query = new KeywordQuery(SPContext.Current.Web) { SourceId = searchResultSource.Id, QueryText = queryText }; // Search query must include the following properties for the friendly URL to work query.SelectProperties.AddRange(new[] { catalogNavigationTermManagedPropertyName, BuiltInManagedProperties.Url.Name, BuiltInManagedProperties.SiteUrl.Name, BuiltInManagedProperties.ListId.Name }); var tables = new SearchExecutor().ExecuteQuery(query); if (tables.Exists(KnownTableTypes.RelevantResults)) { var table = tables.Filter("TableType", KnownTableTypes.RelevantResults).Single(relevantTable => relevantTable.QueryRuleId == Guid.Empty); if (table != null && table.ResultRows.Count == 1 && table.Table.Columns.Contains(BuiltInManagedProperties.Url.Name)) { url = new Uri(table.Table.Rows[0][BuiltInManagedProperties.Url.Name].ToString(), UriKind.Absolute); // Convert the absolute Uri into a relative Uri. This is required for environments using a load balancer, // because we need to ignore the load balancer's port found in the absolute Uri. url = new Uri(url.AbsolutePath, UriKind.Relative); } } return url; }
/// <summary> /// Get the peer url for a SharePoint page /// </summary> /// <param name="currentUrl">The current page url</param> /// <param name="label">The target label to resolve</param> /// <returns>The url of the peer page</returns> public Uri GetPeerPageUrl(Uri currentUrl, VariationLabelInfo label) { if (currentUrl.AbsolutePath.StartsWith("/_layouts", StringComparison.OrdinalIgnoreCase)) { var relativePart = new Uri(currentUrl.PathAndQuery, UriKind.Relative); return new Uri(SPUtility.ConcatUrls(label.TopWebUrl.ToString(), relativePart.ToString())); } try { return new Uri( Variations.GetPeerUrl(SPContext.Current.Web, currentUrl.AbsoluteUri, label.Title), UriKind.Relative); } catch (ArgumentOutOfRangeException) { // TODO: rewrite and unit test the following logic - I do not trust this logic for Managed Path scenarios. this.logger.Info(@"GetPeerUrl: Cannot find variation peer URL with 'Variations.GetPeerUrl'. Using label web URL with path and query strings as navigation URL."); // Keep query string (except source) var queryCollection = HttpUtility.ParseQueryString(currentUrl.Query); queryCollection.Remove("Source"); // Construct peer URL with top web URL + path + query. var topWebUrl = new Uri(label.TopWebUrl + "/"); var pathAndQuerySegments = new List<string>(topWebUrl.Segments.Concat(currentUrl.Segments.Skip(topWebUrl.Segments.Length))); // If any query string, add to segments if (queryCollection.HasKeys()) { pathAndQuerySegments.Add(string.Format(CultureInfo.InvariantCulture, "?{0}", queryCollection)); } return new Uri(topWebUrl, new Uri(string.Join(string.Empty, pathAndQuerySegments), UriKind.Relative)); } }
/// <summary> /// Get the peer url for a taxonomy navigation page (generated by a term set) /// </summary> /// <param name="web">The web.</param> /// <param name="currentUrl">The current page url</param> /// <param name="label">The target label to resolve</param> /// <returns> /// The url of the peer page /// </returns> public Uri GetPeerCatalogCategoryUrl(SPWeb web, Uri currentUrl, VariationLabelInfo label) { // Get current navigation term ID var termId = TaxonomyNavigationContext.Current.NavigationTerm.Id; var labelSiteRelativeUrl = label.TopWebUrl.AbsolutePath; using (var labelWeb = web.Site.OpenWeb(labelSiteRelativeUrl)) { // Create view to return all navigation terms var view = new NavigationTermSetView(labelWeb, StandardNavigationProviderNames.GlobalNavigationTaxonomyProvider) { ExcludeTermsByProvider = false }; var navigationTermSet = TaxonomyNavigation.GetTermSetForWeb(labelWeb, StandardNavigationProviderNames.GlobalNavigationTaxonomyProvider, true).GetWithNewView(view); // Get the matching label navigation term and return it's friendly URL var navigationTerm = this.navigationHelper.FindNavigationTermById(navigationTermSet.Terms, termId); if (navigationTerm != null) { this.logger.Info( "GetPeerCatalogCategoryUrl: Navigation term found for term id '{0}': '{1}'", termId, navigationTerm.Title); var queryString = string.Empty; // Check if some search keywords are present var searchKeywords = HttpUtility.ParseQueryString(currentUrl.Query).Get("k"); if (!string.IsNullOrEmpty(searchKeywords)) { queryString = "?k=" + HttpUtility.UrlEncode(searchKeywords); } return new Uri(navigationTerm.GetResolvedDisplayUrl(queryString), UriKind.Relative); } else { this.logger.Error("GetPeerCatalogCategoryUrl: Navigation term not found for term id '{0}'", termId); return new Uri( Variations.GetPeerUrl(web, currentUrl.AbsolutePath, label.Title), UriKind.Relative); } } }
/// <summary> /// Get the peer url for a page represents a cross site publishing catalog item /// </summary> /// <param name="currentUrl">The current page url</param> /// <param name="label">The target label to resolve</param> /// <param name="associationKeyManagedPropertyName">The content association key search managed property name</param> /// <param name="associationKeyValue">The value of the content association key for the current item</param> /// <param name="languageManagedPropertyName">The language search managed property name</param> /// <param name="catalogNavigationTermManagedPropertyName">The navigation search managed property name used for the friendly url generation</param> /// <returns>The url of the peer page</returns> public Uri GetPeerCatalogItemUrl( Uri currentUrl, VariationLabelInfo label, string associationKeyManagedPropertyName, string associationKeyValue, string languageManagedPropertyName, string catalogNavigationTermManagedPropertyName) { ValidateProperties("GetPeerCatalogItemUrl", associationKeyManagedPropertyName, associationKeyValue, catalogNavigationTermManagedPropertyName); var url = new Uri(Variations.GetPeerUrl(SPContext.Current.Web, currentUrl.AbsoluteUri, label.Title), UriKind.Relative); var searchResultSource = this.searchHelper.GetResultSourceByName(SPContext.Current.Site, LocalSharePointResultsSourceName, SearchObjectLevel.Ssa); // We take the Title of the Label because the Label.Language is always a language from a language pack (supported). Sometimes, we deal with Not implemented language (ie Inuktitut "IU"). // Our workaround is to set the Title as the agnostic language label ("en", "fr", "iu", etc). // For backward compatibility purpose, we will test the length of the Title. If it's not 2, we will fallback on the Language of the Label. // This is not 100% robust but it the only way we found to deal with unsupported language. var labelLocaleAgnosticLanguage = label.Title.Length == 2 ? label.Title : label.Language.Split('-').FirstOrDefault(); var queryText = string.Format( CultureInfo.InvariantCulture, "{0}:{1} {2}={3}", associationKeyManagedPropertyName, associationKeyValue, languageManagedPropertyName, labelLocaleAgnosticLanguage); var query = new KeywordQuery(SPContext.Current.Web) { SourceId = searchResultSource.Id, QueryText = queryText }; // Search query must include the following properties for the friendly URL to work query.SelectProperties.AddRange(new[] { catalogNavigationTermManagedPropertyName, BuiltInManagedProperties.Url, BuiltInManagedProperties.SiteUrl, BuiltInManagedProperties.ListId }); var tables = new SearchExecutor().ExecuteQuery(query); if (tables.Exists(KnownTableTypes.RelevantResults)) { var table = tables.Filter("TableType", KnownTableTypes.RelevantResults).Single(relevantTable => relevantTable.QueryRuleId == Guid.Empty); if (table != null && table.ResultRows.Count == 1 && table.Table.Columns.Contains(BuiltInManagedProperties.Url)) { url = new Uri(table.Table.Rows[0][BuiltInManagedProperties.Url].ToString()); } } return url; }