public void OnActionExecuting(ActionExecutingContext context) { if (!context.ActionArguments.Any()) { return; } var bundleFile = context.ActionArguments.First().Value as BundleRequestModel; ICacheBuster cacheBuster; RequestModel file = null; if (bundleFile != null) { cacheBuster = _cacheBusterResolver.GetCacheBuster(bundleFile.Bundle.GetBundleOptions(_bundleManager, bundleFile.Debug).GetCacheBusterType()); } else { //the default for any dynamically (non bundle) file is the default bundle options in production cacheBuster = _cacheBusterResolver.GetCacheBuster(_bundleManager.GetDefaultBundleOptions(false).GetCacheBusterType()); file = context.ActionArguments.First().Value as RequestModel; } if (file != null) { FileResult result; DateTime lastWrite; if (TryGetCachedCompositeFileResult(_fileSystemHelper, cacheBuster, file.FileKey, file.Compression, file.Mime, out result, out lastWrite)) { file.LastFileWriteTime = lastWrite; context.Result = result; } } }
public CompositeFileModel(IHasher hasher, IUrlManager urlManager, IActionContextAccessor accessor, IRequestHelper requestHelper, IBundleManager bundleManager, CacheBusterResolver cacheBusterResolver) : base("file", urlManager, accessor, requestHelper) { //Creates a single hash of the full url (which can include many files) FileKey = hasher.Hash(string.Join(".", ParsedPath.Names)); CacheBuster = cacheBusterResolver.GetCacheBuster(bundleManager.GetDefaultBundleOptions(false).GetCacheBusterType()); }
private async Task ProcessFileImpl(IWebFile file, BundleOptions bundleOptions, BundleContext bundleContext) { if (file == null) { throw new ArgumentNullException(nameof(file)); } var extension = Path.GetExtension(file.FilePath); var fileWatchEnabled = bundleOptions?.FileWatchOptions.Enabled ?? false; Lazy <IFileInfo> fileInfo; var cacheBuster = bundleOptions != null ? _cacheBusterResolver.GetCacheBuster(bundleOptions.GetCacheBusterType()) : _cacheBusterResolver.GetCacheBuster(_bundleManager.GetDefaultBundleOptions(false).GetCacheBusterType()); //the default for any dynamically (non bundle) file is the default bundle options in production var cacheFile = _fileSystemHelper.GetCacheFilePath(file, fileWatchEnabled, extension, cacheBuster, out fileInfo); var exists = File.Exists(cacheFile); //check if it's in cache if (exists) { _logger.LogDebug($"File already in cache '{file.FilePath}', type: {file.DependencyType}, cacheFile: {cacheFile}, watching? {fileWatchEnabled}"); } else { if (file.Pipeline.Processors.Count > 0) { _logger.LogDebug($"Processing file '{file.FilePath}', type: {file.DependencyType}, cacheFile: {cacheFile}, watching? {fileWatchEnabled} ..."); var contents = await _fileSystemHelper.ReadContentsAsync(fileInfo.Value); var watch = new Stopwatch(); watch.Start(); //process the file var processed = await file.Pipeline.ProcessAsync(new FileProcessContext(contents, file, bundleContext)); watch.Stop(); _logger.LogDebug($"Processed file '{file.FilePath}' in {watch.ElapsedMilliseconds}ms"); //save it to the cache path await _fileSystemHelper.WriteContentsAsync(cacheFile, processed); } else { // we can just copy the the file as-is to the cache file _fileSystemHelper.CopyFile(fileInfo.Value.PhysicalPath, cacheFile); } } //If file watching is enabled, then watch it - this is regardless of whether the cache file exists or not // since after app restart if there's already a cache file, we still want to watch the file set if (fileWatchEnabled) { // watch this file for changes, if the file is already watched this will do nothing _fileSystemHelper.Watch(file, fileInfo.Value, bundleOptions, FileModified); } }
private async Task ProcessFileImpl(IWebFile file, BundleOptions bundleOptions, BundleContext bundleContext) { if (file == null) { throw new ArgumentNullException(nameof(file)); } var extension = Path.GetExtension(file.FilePath); var fileWatchEnabled = bundleOptions?.FileWatchOptions.Enabled ?? false; Lazy <IFileInfo> fileInfo; var cacheBuster = bundleOptions != null ? _cacheBusterResolver.GetCacheBuster(bundleOptions.GetCacheBusterType()) : _cacheBusterResolver.GetCacheBuster(_bundleManager.GetDefaultBundleOptions(false).GetCacheBusterType()); //the default for any dynamically (non bundle) file is the default bundle options in production var cacheFile = _fileSystemHelper.GetCacheFilePath(file, fileWatchEnabled, extension, cacheBuster, out fileInfo); //check if it's in cache if (!File.Exists(cacheFile)) { var contents = await _fileSystemHelper.ReadContentsAsync(fileInfo.Value); //process the file var processed = await file.Pipeline.ProcessAsync(new FileProcessContext(contents, file, bundleContext)); //save it to the cache path await _fileSystemHelper.WriteContentsAsync(cacheFile, processed); } //If file watching is enabled, then watch it - this is regardless of whether the cache file exists or not // since after app restart if there's already a cache file, we still want to watch the file set if (fileWatchEnabled) { // watch this file for changes, if the file is already watched this will do nothing _fileSystemHelper.Watch(file, fileInfo.Value, bundleOptions, FileModified); } }
/// <summary> /// Generates the URLs for a dynamically registered set of files (non pre-defined bundle) /// </summary> /// <param name="files"></param> /// <param name="fileType"></param> /// <param name="pipeline"></param> /// <param name="debug"></param> /// <returns></returns> private async Task <IEnumerable <string> > GenerateUrlsAsync( IEnumerable <IWebFile> files, WebFileType fileType, PreProcessPipeline pipeline = null, bool debug = false) { var result = new List <string>(); var orderedFiles = _fileSetGenerator.GetOrderedFileSet(files, pipeline ?? _processorFactory.CreateDefault(fileType)); if (debug) { return(orderedFiles.Select(x => x.FilePath)); } var compression = _requestHelper.GetClientCompression(_httpContextAccessor.HttpContext.Request.Headers); //Get the file collection used to create the composite URLs and the external requests var fileBatches = _fileBatcher.GetCompositeFileCollectionForUrlGeneration(orderedFiles); var cacheBuster = _cacheBusterResolver.GetCacheBuster(_bundleManager.GetDefaultBundleOptions(debug).GetCacheBusterType()); foreach (var batch in fileBatches) { //if it's external, the rule is that a WebFileBatch can only contain a single external file // it's path will be normalized as an external url so we just use it if (batch.IsExternal) { result.Add(batch.Single().Original.FilePath); } else { //Get the URLs for the batch, this could be more than one resulting URL depending on how many // files are in the batch and the max url length var compositeUrls = _urlManager.GetUrls( batch.Select(x => x.Hashed), fileType == WebFileType.Css ? ".css" : ".js", cacheBuster); foreach (var u in compositeUrls) { //now we need to determine if these files have already been minified var compositeFilePath = _fileSystemHelper.GetCurrentCompositeFilePath(cacheBuster, compression, u.Key); if (!File.Exists(compositeFilePath)) { using (var bundleContext = BundleContext.CreateEmpty()) { //need to process/minify these files - need to use their original paths of course foreach (var file in batch.Select(x => x.Original)) { await _preProcessManager.ProcessAndCacheFileAsync(file, null, bundleContext); } } } result.Add(u.Url); } } } return(result); }