CssRewriteUrlTransform with or without virtual directory

27,661

Solution 1

I am not sure to fully understand your problem, but seeing http://localhost here seems wrong. You should never use an absolute URL for your bundles.

For me CssRewriteUrlTransform works perfectly, here is how I use it:

bundles.Add(new StyleBundle("~/bundles/css").Include(
                "~/Content/css/*.css", new CssRewriteUrlTransform()));

"Bundles" is virtual.

Does this helps?

Update

I was confused with the "VirtualDir" thing, as you are talking about IIS VirtualDir, and I was thinking Bundle VirtualDir! It's true that in this case CssRewriteUrlTransform will rewrite URLs to the Host, not to the Host/VirtualDir URI.

To do that, you have to derive CssRewriteUrlTransform to make it do what you need it to. There is a good discussion here: ASP.NET MVC4 Bundling with Twitter Bootstrap

Seems the best answer is there:http://aspnetoptimization.codeplex.com/workitem/83

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

Solution 2

I had the same problem. This is how I fixed it:

private class ProperUrlRewrite : IItemTransform
{
    private static string RebaseUrlToAbsolute(string baseUrl, string url)
    {
        if (string.IsNullOrWhiteSpace(url) || string.IsNullOrWhiteSpace(baseUrl) || url.StartsWith("/", StringComparison.OrdinalIgnoreCase) || url.Contains(':'))
            return url;
        return VirtualPathUtility.Combine(baseUrl, url);
    }
    private static Regex UrlPattern = new Regex("url\\s*\\(['\"]?(?<url>[^)]+?)['\"]?\\)");
    public string Process(string includedVirtualPath, string input)
    {
        if (includedVirtualPath == null)
            throw new ArgumentNullException("includedVirtualPath");
        if (string.IsNullOrWhiteSpace(input))
            return input;

        string directory = VirtualPathUtility.GetDirectory(VirtualPathUtility.ToAbsolute(includedVirtualPath));
        if (!directory.EndsWith("/", StringComparison.OrdinalIgnoreCase))
            directory += "/";
        return UrlPattern.Replace(input, match => "url(" + ProperUrlRewrite.RebaseUrlToAbsolute(directory, match.Groups["url"].Value) + ")");
    }
}

I know it's far from perfect and there are plenty of edge cases where this can go wrong (I'm not sure you can parse a CSS file with a regex in the first place - though this is exactly what the original CssRewriteUrlTransform does), but so far it holds...

Solution 3

The 'CssRewriteUrlTransform' works just fine for applications that DOESN'T run on top of a virtual directory.

So, if your app runs on http://your-site.com/ it runs just fine, but if runs on http://your-site.com/your-app/ you'll have 404 for all your images, because the default 'CssFixRewriteUrlTransform' is referencing your images with a '/'.

Use this:

public class CssFixRewriteUrlTransform: IItemTransform {

    private static string ConvertUrlsToAbsolute(string baseUrl, string content) {
        if (string.IsNullOrWhiteSpace(content)) {
            return content;
        }
        var regex = new Regex("url\\(['\"]?(?<url>[^)]+?)['\"]?\\)");
        return regex.Replace(content, match = > string.Concat("url(", RebaseUrlToAbsolute(baseUrl, match.Groups["url"].Value), ")"));
    }

    public string Process(string includedVirtualPath, string input) {
        if (includedVirtualPath == null) {
            throw new ArgumentNullException("includedVirtualPath");
        }
        var directory = VirtualPathUtility.GetDirectory(includedVirtualPath);
        return ConvertUrlsToAbsolute(directory, input);
    }

    private static string RebaseUrlToAbsolute(string baseUrl, string url) {
        if (string.IsNullOrWhiteSpace(url) || string.IsNullOrWhiteSpace(baseUrl) || url.StartsWith("/", StringComparison.OrdinalIgnoreCase)) {
            return url;
        }
        if (!baseUrl.EndsWith("/", StringComparison.OrdinalIgnoreCase)) {
            baseUrl = string.Concat(baseUrl, "/");
        }
        return VirtualPathUtility.ToAbsolute(string.Concat(baseUrl, url));
    }
}

Note: delete all file css with .min.css, because if don't it doesn't fix.

Share:
27,661
Anders
Author by

Anders

I'm a committed and driven consultant who enjoy working in customer-oriented projects. I have good experience in designing and developing customer-specific IT solutions in .NET. I'm passionate about "Continuous learning" and read blogs and test new technologies regulary. I'm aiming at always leaving my projects with well structured code, which together with well-balanced design solutions makes them easy to maintain.

Updated on July 05, 2022

Comments

  • Anders
    Anders almost 2 years

    We are using MVC Bundling in our site, CssRewriteUrlTransform makes sure that the image urls work from the dynamic bundle css file.

    But this only works when not using a virtual directory, i.e

    http://localhost/VirttualDir does not work but http://localhost/ does. This is because the CssRewriteUrlTransform tranform does not take the virtual folder into account when rewriting the url. So if a image real path is localhost/vdir/content/img/foo.png it will rewrite it to localhost/content/img/foo.png which is wrong

  • Vilx-
    Vilx- over 10 years
    The problem appears when your application isn't hosted at the server root, but in a virtual directory. Like /path/to/my/appRoot/.
  • Anders
    Anders over 10 years
    Thanks will check it out!
  • Ole Tolshave
    Ole Tolshave about 8 years
    The idea of removing the ".min.css" file helped me out. I guess if the file exists then that file is included directly as an optimization and then the rewriting never takes place.
  • Robert Slaney
    Robert Slaney about 8 years
    You need to take into account data uri formats. Ignore urls starting with "data:" in your RebaseUrlToAbsolute function
  • jonmeyer
    jonmeyer over 6 years
    This put me on the right track but did not work for url( ) that contained a AbsoluteUri already, i needed to detect that so i added a Uri.TryCreate inside a custom version of CssRewriteUrlTranform instead of using a wrapper.
  • Mahanthesh Kumbar
    Mahanthesh Kumbar over 4 years
    @jonmeyer Do you have sample code how it is achieved without the transform.
  • Thulasiram
    Thulasiram about 4 years
    Working Fine. Thanks :)
  • this.myself
    this.myself almost 3 years
    The problem may also appear when your application is behind a portal where some forwarding and so on is done (don't know exact offical wording for our setup).