private string HeadCacheKey (Uri currentUrl, ConfigSection.HeadCachingOption headCachingOption) { const string keyPrefix = "HeadCacheKey__"; switch (headCachingOption) { case ConfigSection.HeadCachingOption.PerSite: // Always return the same key for all pages return keyPrefix; case ConfigSection.HeadCachingOption.PerFolder: // Key is based on domain + folder, but not the file // // If no .aspx file is specific, AbsoluteUri will still include // the actual file, such as default.aspx. int idxLastSlash = currentUrl.AbsoluteUri.LastIndexOf ('/'); if (idxLastSlash == -1) { return keyPrefix + currentUrl.ToString (); } return keyPrefix + currentUrl.AbsoluteUri.Substring (0, idxLastSlash); case ConfigSection.HeadCachingOption.PerPage: // Key is based on folder + file, but not on query string return keyPrefix + currentUrl.AbsolutePath; case ConfigSection.HeadCachingOption.PerUrl: return keyPrefix + currentUrl.ToString (); default: throw new Exception ( "HeadCacheKey - unknown headCachingOption: " + headCachingOption.ToString ()); } }
/// <summary> /// /// </summary> /// <param name="headHtmlSb"></param> /// <param name="groupRegexp"></param> /// <param name="fileType"></param> /// <param name="tagTemplate"></param> /// <param name="totalFileNames"></param> /// <param name="combineFiles"></param> /// <param name="placeCombinedFilesAtEnd"> /// This is only relevant if combineFiles equals All. /// If placeCombinedFilesAtEnd is true, the tag loading the combined file /// replaces the very last file group (important if you're loading js, because it means that if any /// js is dependent on a library loaded from a CDN, all the js will load after that library. /// /// If placeCombinedFilesAtEnd is false, the tag replaces the very first file group. /// You'd use this with CSS, to get it load possibly sooner than the js. /// </param> /// <param name="urlProcessor"></param> private void ProcessFileType( string headHtml, string groupRegexp, FileTypeUtilities.FileType fileType, string tagTemplate, List<string> totalFileNames, ConfigSection.CombineOption combineFiles, bool placeCombinedFilesAtEnd, bool minifyCSS, bool minifyJavaScript, UrlProcessor urlProcessor) { List<groupInfo> allGroups = new List<groupInfo>(); List<Uri> totalFileUrlsList = new List<Uri>(); Regex r = new Regex(groupRegexp, RegexOptions.IgnoreCase); Match m = r.Match(headHtml); // Visit each group of script or link tags. Record the html of each file group // and a list of the urls in the tags in that file group in allGroups. while (m.Success) { string fileGroup = m.Value; CaptureCollection fileUrls = m.Groups["url"].Captures; // Visit the src or href of each individual script or link tag in the group, // and add to a list of urls. List<Uri> fileUrlsList = new List<Uri>(); for (int j = 0; j < fileUrls.Count; j++) { Uri fileUrl = new Uri(HttpContext.Current.Request.Url, fileUrls[j].Value); fileUrlsList.Add(fileUrl); totalFileUrlsList.Add(fileUrl); } allGroups.Add(new groupInfo() { fileGroup = fileGroup, fileUrlsList = fileUrlsList }); m = m.NextMatch(); } // Process each file group in allGroups switch (combineFiles) { case ConfigSection.CombineOption.None: // In each group, process all URLs individually into tags. // Note that CombinedFile.Url not only has the ability to combine urls, but also // to insert version info - and we still want that to be able to use far future cache expiry, // even if not combining files. // Concatenate the tags and replace the group with the concatenated tags. foreach (groupInfo g in allGroups) { StringBuilder tagsInGroup = new StringBuilder(); foreach (Uri u in g.fileUrlsList) { string versionedUrl = CombinedFile.Url( HttpContext.Current, new List<Uri>(new Uri[] { u }), fileType, minifyCSS, minifyJavaScript, urlProcessor, totalFileNames); string versionedFileTag = string.Format(tagTemplate, versionedUrl); tagsInGroup.Append(versionedFileTag); } // Be sure to trim the group before storing it (that is, remove space at the front and end). // If you don't, you may store a group with white space at either end, that then doesn't match // a group in some other file that is exactly the same, except for the white space at either end. Replacements.Add(new Replacement { original = g.fileGroup.Trim(), replacement = tagsInGroup.ToString() }); } break; case ConfigSection.CombineOption.PerGroup: // In each group, process all URLs together into a combined tag. // Replace the group with that one tag. foreach (groupInfo g in allGroups) { string combinedFileUrl = CombinedFile.Url( HttpContext.Current, g.fileUrlsList, fileType, minifyCSS, minifyJavaScript, urlProcessor, totalFileNames); string combinedFileTag = string.Format(tagTemplate, combinedFileUrl); Replacements.Add(new Replacement { original = g.fileGroup.Trim(), replacement = combinedFileTag }); } break; case ConfigSection.CombineOption.All: // Combine all urls into a single tag. Then insert that tag in the head. // Also, remove all groups. { string combinedFileUrl = CombinedFile.Url( HttpContext.Current, totalFileUrlsList, fileType, minifyCSS, minifyJavaScript, urlProcessor, totalFileNames); string combinedFileTag = string.Format(tagTemplate, combinedFileUrl); int idxFileGroupToReplace = placeCombinedFilesAtEnd ? (allGroups.Count - 1) : 0; Replacements.Add( new Replacement { original = allGroups[idxFileGroupToReplace].fileGroup.Trim(), replacement = combinedFileTag }); // Replace all file groups with empty string, except for the one // we just replaced with the tag. allGroups.RemoveAt(idxFileGroupToReplace); foreach (groupInfo g in allGroups) { Replacements.Add( new Replacement { original = g.fileGroup.Trim(), replacement = "" }); } } break; default: throw new ArgumentException("ProcessFileType - combineFiles=" + combineFiles.ToString()); } }