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
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
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...
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.
I have problems with url that contains "data" and even a url inner another one, so I have to re-do the regex, this is my solution:
public string Process(string includedVirtualPath, string input)
{
if (includedVirtualPath == null)
{
throw new ArgumentNullException(nameof(includedVirtualPath));
}
if (string.IsNullOrWhiteSpace(input))
{
return input;
}
var directory = VirtualPathUtility.GetDirectory(includedVirtualPath);
if (!directory.EndsWith("/", StringComparison.OrdinalIgnoreCase))
{
directory += "/";
}
return new Regex(@"url\s*\(\s*([\'""]?)(?<scheme>(?:(?:data:)|(?:https?:))?)(?<url>(\\\1|.)*?)\1\s*\)")
.Replace(input, match => string.Concat(
"url(",
match.Groups[1].Value,
match.Groups["scheme"].Value,
match.Groups["scheme"].Value == "" ?
RebaseUrlToAbsolute(directory, match.Groups["url"].Value) :
match.Groups["url"].Value,
match.Groups[1].Value,
")"
));
}
private static string RebaseUrlToAbsolute(string baseUrl, string url)
{
if (string.IsNullOrWhiteSpace(url) || string.IsNullOrWhiteSpace(baseUrl)
|| url.StartsWith("/", StringComparison.OrdinalIgnoreCase))
{
return url;
}
return VirtualPathUtility.ToAbsolute(string.Concat(baseUrl, url));
}
}
来源:https://stackoverflow.com/questions/19765238/cssrewriteurltransform-with-or-without-virtual-directory