andrewdavey / cassette

Manages .NET web application assets (scripts, css and templates)
http://getcassette.net
MIT License
534 stars 143 forks source link

turn off cache busting locally for easy debug #315

Closed axelnormand closed 9 years ago

axelnormand commented 12 years ago

Hello,

Is there any way to turn off the cache busting "?xxxxxxxxxxxxx" appended to un-minified files when running locally (ie debug on)?

If i set a breakpoint in chrome, then change the file and reload the page the breakpoint is lost as a differenent cache busting parameter is added to the filename so chrome thinks its a different file.

Many thanks

mickdelaney commented 11 years ago

anyone come up with a solution for this??

AndyOsipov commented 10 years ago

+1 for this feature to be added

axelnormand commented 9 years ago

In the end i've used the following custom code which will turn off the hash when debug on (As specified in web.config) Code adapted from this pull request (thanks!): https://github.com/andrewdavey/cassette/pull/375

/// <summary>
    /// register our custom url generator
    /// </summary>
    public class CustomCassetteConfig : IConfiguration<Cassette.TinyIoC.TinyIoCContainer>
    {
        public void Configure(TinyIoCContainer container)
        {
            container.Register<IUrlGenerator>(
                (c, n) =>
                    new CustomUrlGenerator(c.Resolve<IUrlModifier>(), c.Resolve<CassetteSettings>().SourceDirectory,
                        "cassette.axd/"));
        }
    }
/// <summary>
    /// don't add cache busting '?xxxxxx' to assets under cassette.axd in debug mode so can keep breakpoint in chrome when file changes
    /// </summary>
    public class CustomUrlGenerator : IUrlGenerator
    {
        private readonly IUrlGenerator _cassetteUrlGenerator; //most calls just use the original Cassette UrlGenerator
        private readonly bool _useHash;
        private readonly string _cassetteHandlerPrefix;
        private readonly IUrlModifier _urlModifier;

        public CustomUrlGenerator(IUrlModifier urlModifier, IDirectory sourceDirectory, string cassetteHandlerPrefix)
        {
            _cassetteUrlGenerator = new UrlGenerator(urlModifier, sourceDirectory, cassetteHandlerPrefix);
            _cassetteHandlerPrefix = cassetteHandlerPrefix;
            _urlModifier = urlModifier;

            //only add hash in live
            _useHash = !HttpContext.Current.IsDebuggingEnabled;
        }

        public string CreateBundleUrl(Cassette.Bundle bundle)
        {
            return _cassetteUrlGenerator.CreateBundleUrl(bundle);
        }

        public string CreateAssetUrl(IAsset asset)
        {
            // "~/directory/file.js" --> "cassette.axd/asset/directory/file.js?hash"
            // Asset URLs are only used in debug mode. The hash is placed in the querystring, not the path.
            // This maintains the asset directory structure i.e. two assets in the same directory appear together in web browser JavaScript development tooling.

            var assetPath = asset.Path.Substring(1);
            var url = _cassetteHandlerPrefix + "asset" + assetPath;

            if (_useHash)
            {
                var hash = asset.Hash.ToHexString();
                url = url + "?" + hash;
            }

            return _urlModifier.Modify(url);
        }

        public string CreateRawFileUrl(string filename)
        {
            return _cassetteUrlGenerator.CreateRawFileUrl(filename);
        }

        string IUrlGenerator.CreateRawFileUrl(string filename, string hash)
        {
            if (filename.StartsWith("~") == false)
            {
                throw new ArgumentException(
                    "Image filename must be application relative (starting with '~'). Filename: " + filename);
            }

            var hashWithPrefix = string.Empty;
            if (_useHash)
            {
                hashWithPrefix = "-" + hash;
            }

            // "~\example\image.png" --> "/example/image-hash.png"
            var path = ConvertToForwardSlashes(filename).Substring(1);
            path = UriEscapePathSegments(path);

            var index = path.LastIndexOf('.');
            if (index >= 0)
            {
                path = path.Insert(index, hashWithPrefix);
            }
            else
            {
                path = path + hashWithPrefix;
            }

            var url = _cassetteHandlerPrefix + "file" + path;
            return _urlModifier.Modify(url);
        }

        public string CreateCachedFileUrl(string filename)
        {
            return _cassetteUrlGenerator.CreateCachedFileUrl(filename);
        }

        public string CreateAbsolutePathUrl(string applicationRelativePath)
        {
            return _cassetteUrlGenerator.CreateAbsolutePathUrl(applicationRelativePath);
        }

        private string ConvertToForwardSlashes(string path)
        {
            return path.Replace('\\', '/');
        }

        /// <summary>
        /// Escape each part of the URL between the slashes.
        /// </summary>
        private string UriEscapePathSegments(string path)
        {
            return string.Join(
                "/",
                path.Split('/').Select(Uri.EscapeDataString).ToArray()
                );
        }
    }
aeslinger0 commented 8 years ago

Thanks @axelnormand! I had to change the line _useHash = !HttpContext.Current.IsDebuggingEnabled; because it was throwing a null reference exception, but otherwise this works great. I changed it to:

#if DEBUG
            _useHash = false;
#else
            _useHash = true;
#endif