private static DomainAndUri MapDomain(DomainAndUri[] domainAndUris, Dictionary<string, string[]> qualifiedSites, string currentAuthority) { if (domainAndUris == null) throw new ArgumentNullException("domainAndUris"); if (!domainAndUris.Any()) throw new ArgumentException("Cannot be empty.", "domainAndUris"); // we do our best, but can't do the impossible if (qualifiedSites == null) return domainAndUris.First(); // find a site that contains the current authority var currentSite = qualifiedSites.FirstOrDefault(site => site.Value.Contains(currentAuthority)); // if current belongs to a site - try to pick the first element // from domainAndUris that also belongs to that site var ret = currentSite.Equals(default(KeyValuePair<string, string[]>)) ? null : domainAndUris.FirstOrDefault(d => currentSite.Value.Contains(d.Uri.GetLeftPart(UriPartial.Authority))); // no match means that either current does not belong to a site, or the site it belongs to // does not contain any of domainAndUris. Yet we have to return something. here, it becomes // a bit arbitrary. // look through sites in order and pick the first domainAndUri that belongs to a site ret = ret ?? qualifiedSites .Where(site => site.Key != currentSite.Key) .Select(site => domainAndUris.FirstOrDefault(domainAndUri => site.Value.Contains(domainAndUri.Uri.GetLeftPart(UriPartial.Authority)))) .FirstOrDefault(domainAndUri => domainAndUri != null); // random, really ret = ret ?? domainAndUris.First(); return ret; }
/// <summary> /// Filters a list of <c>DomainAndUri</c> to pick those that best matches the current request. /// </summary> /// <param name="current">The Uri of the current request.</param> /// <param name="domainAndUris">The list of <c>DomainAndUri</c> to filter.</param> /// <param name="excludeDefault">A value indicating whether to exclude the current/default domain.</param> /// <returns>The selected <c>DomainAndUri</c> items.</returns> /// <remarks>The filter must return something, even empty, else an exception will be thrown.</remarks> public virtual IEnumerable<DomainAndUri> MapDomains(Uri current, DomainAndUri[] domainAndUris, bool excludeDefault) { var currentAuthority = current.GetLeftPart(UriPartial.Authority); KeyValuePair<string, string[]>[] candidateSites = null; IEnumerable<DomainAndUri> ret = domainAndUris; using (ConfigReadLock) // so nothing changes between GetQualifiedSites and access to bindings { var qualifiedSites = GetQualifiedSitesInsideLock(current); if (excludeDefault) { // exclude the current one (avoid producing the absolute equivalent of what GetUrl returns) var hintWithSlash = current.EndPathWithSlash(); var hinted = domainAndUris.FirstOrDefault(d => d.Uri.EndPathWithSlash().IsBaseOf(hintWithSlash)); if (hinted != null) ret = ret.Where(d => d != hinted); // exclude the default one (avoid producing a possible duplicate of what GetUrl returns) // only if the default one cannot be the current one ie if hinted is not null if (hinted == null && domainAndUris.Any()) { // it is illegal to call MapDomain if domainAndUris is empty // also, domainAndUris should NOT contain current, hence the test on hinted var mainDomain = MapDomain(domainAndUris, qualifiedSites, currentAuthority); // what GetUrl would get ret = ret.Where(d => d != mainDomain); } } // we do our best, but can't do the impossible if (qualifiedSites == null) return ret; // find a site that contains the current authority var currentSite = qualifiedSites.FirstOrDefault(site => site.Value.Contains(currentAuthority)); // if current belongs to a site, pick every element from domainAndUris that also belong // to that site -- or to any site bound to that site if (!currentSite.Equals(default(KeyValuePair<string, string[]>))) { candidateSites = new[] { currentSite }; if (_bindings != null && _bindings.ContainsKey(currentSite.Key)) { var boundSites = qualifiedSites.Where(site => _bindings[currentSite.Key].Contains(site.Key)); candidateSites = candidateSites.Union(boundSites).ToArray(); // .ToArray ensures it is evaluated before the configuration lock is exited } } } // if we are able to filter, then filter, else return the whole lot return candidateSites == null ? ret : ret.Where(d => { var authority = d.Uri.GetLeftPart(UriPartial.Authority); return candidateSites.Any(site => site.Value.Contains(authority)); }); }