/// <summary> /// Finds the domain that best matches the current uri, into an enumeration of domains. /// </summary> /// <param name="domains">The enumeration of Umbraco domains.</param> /// <param name="current">The uri of the current request, or null.</param> /// <param name="defaultToFirst">A value indicating whether to return the first domain of the list when no domain matches.</param> /// <returns>The domain and its normalized uri, that best matches the current uri, else the first domain (if <c>defaultToFirst</c> is <c>true</c>), else null.</returns> public static DomainAndUri DomainMatch(IEnumerable <Domain> domains, Uri current, bool defaultToFirst) { // sanitize the list to have proper uris for comparison (scheme, path end with /) // we need to end with / because example.com/foo cannot match example.com/foobar // we need to order so example.com/foo matches before example.com/ var scheme = current == null ? Uri.UriSchemeHttp : current.Scheme; var domainsAndUris = domains .Where(d => !IsWildcardDomain(d)) .Select(d => SanitizeForBackwardCompatibility(d)) .Select(d => new { Domain = d, UriString = UriUtility.EndPathWithSlash(UriUtility.StartWithScheme(d.Name, scheme)) }) .OrderByDescending(t => t.UriString) .Select(t => new DomainAndUri { Domain = t.Domain, Uri = new Uri(t.UriString) }); if (!domainsAndUris.Any()) { return(null); } DomainAndUri domainAndUri; if (current == null) { // take the first one by default domainAndUri = domainsAndUris.First(); } else { // look for a domain that would be the base of the hint // else take the first one by default var hintWithSlash = current.EndPathWithSlash(); domainAndUri = domainsAndUris .FirstOrDefault(t => t.Uri.IsBaseOf(hintWithSlash)); if (domainAndUri == null && defaultToFirst) { domainAndUri = domainsAndUris.First(); } } if (domainAndUri != null) { domainAndUri.Uri = domainAndUri.Uri.TrimPathEndSlash(); } return(domainAndUri); }