37
Vote

CssRewriteUrlTransform ignores application root when resolving absolute paths

description

When I host an application in a subdirectory (say, localhost/myapp) and I set web.config debug="false", CSS urls are made absolutely relative to the site root rather than the application root.

Consider this config:
BundleTable.Bundles.Add(new StyleBundle("~/content/theme-default")
                                        .Include("~/Content/2012.2.607/telerik.common.min.css")
                                        .Include("~/Content/2012.2.607/telerik.metro.min.css", new CssRewriteUrlTransform()));
telerik.metro.min.css includes url(Metro/Sprite.png). The result of CssRewriteUrlTransform is that such URLs are rewritten to /content/Metro/Sprite.png instead of the correct /content/2012.2.607/Metro/Sprite.png.

CssRewriteUrlTransform.Process contains the following code:
return CssRewriteUrlTransform.ConvertUrlsToAbsolute(VirtualPathUtility.GetDirectory(includedVirtualPath.Substring(1)), input);
Since includedVirtualPath must start with "~/" (as far as I can tell), this causes the absolute path issue. Removing .Substring(1) seems to work fine.

I'm using 1.1.0-beta1 prerelease package in NuGet.

comments

HaoK wrote Apr 30, 2013 at 9:31 PM

This is actually just another issue with optimizations in general not working correctly when the app is running as a virtual directory. I cannot repro this behavior normally. Moving to backlog out of 1.1 for now

Mohamed_Meligy wrote May 2, 2013 at 6:27 AM

Well, I'd be keen on seeing how far I can go with fixing it myself, if the code was available to fork.

MadBender wrote Aug 9, 2013 at 8:09 AM

Temporary workaround is to make a wrapper that will call CssRewriteUrlTransform with the fixed path.
    public class CssRewriteUrlTransformWrapper : IItemTransform
    {
        public string Process(string includedVirtualPath, string input)
        {           
            return new CssRewriteUrlTransform().Process("~" + VirtualPathUtility.ToAbsolute(includedVirtualPath), input);           
        }
    }
Use this class instead of CssRewriteUrlTransform

rslaney wrote Apr 2, 2014 at 1:34 AM

If you want to replicate this easily in VS2013 and IISExpress, just specify a virtual directory in the project settings, then run the site with debug="false" in the web.config system.web/compilation key.

The problem is easily fixed by changing the CssRewriteUrlTransform as follows
  • Use VirtualPathUtility.Combine in RebaseUrlToAbsolute instead of VirtualPathUtility.GetDirectory in Process
    public string Process(string includedVirtualPath, string input) {
        if (includedVirtualPath == null)
        {
            throw new ArgumentNullException("includedVirtualPath");
        }
        return ConvertUrlsToAbsolute(includedVirtualPath, input);
    }

    internal static string RebaseUrlToAbsolute(string baseUrl, string url)
    {
        if ((string.IsNullOrWhiteSpace(url) || string.IsNullOrWhiteSpace(baseUrl)) || url.StartsWith("/", StringComparison.OrdinalIgnoreCase))
        {
            return VirtualPathUtility.ToAbsolute("~" + url);
        }
        return VirtualPathUtility.ToAbsolute( VirtualPathUtility.Combine(baseUrl, url));
    }
Out of interest, the MVC5 template conveniently worked around the issue with the bootstrap.css by moving the font files to the root of the application which "just happened" to match the relative path to the bundle.

benmccallum wrote Dec 15, 2015 at 10:17 AM

Fix for this now added to my AspNetBundling NuGet package which resolves a bunch of other issues in the standard transformer, particularly around using data-uris. Open-sourced on GitHub too.

Just do:
  1. Install-Package AspNetBundling
  2. Replace CssRewriteUrlTransform with CssRewriteUrlTransformFixed