MVC4 StyleBundle不能解析图像

我的问题与此类似:

ASP.NET MVC 4缩小&背景图片< / >

除了我想坚持MVC自己的捆绑如果我可以的话。我有一个大脑崩溃试图找出什么是正确的模式是指定样式包,如独立的css和图像集,如jQuery UI工作。

我有一个典型的MVC网站结构与/Content/css/包含我的基本CSS,如styles.css。在这个css文件夹中,我还有一些子文件夹,比如/jquery-ui,其中包含它的css文件和/images文件夹。jQuery UI CSS中的图像路径是相对于该文件夹的,我不想打乱它们。

根据我的理解,当我指定StyleBundle时,我需要指定一个虚拟路径,它也不匹配真实的内容路径,因为(假设我忽略了到内容的路由)IIS将尝试将该路径解析为物理文件。所以我指定:

bundles.Add(new StyleBundle("~/Content/styles/jquery-ui")
.Include("~/Content/css/jquery-ui/*.css"));

呈现的使用:

@Styles.Render("~/Content/styles/jquery-ui")

我可以看到请求发送到:

http://localhost/MySite/Content/styles/jquery-ui?v=nL_6HPFtzoqrts9nwrtjq0VQFYnhMjY5EopXsK8cxmg1

返回正确的,最小化的CSS响应。 但随后浏览器会发送一个相对链接图像的请求:

http://localhost/MySite/Content/styles/images/ui-bg_highlight-soft_100_eeeeee_1x100.png

它是404

我知道我的URL jquery-ui的最后一部分是一个无扩展的URL,是我的包的处理程序,所以我可以看到为什么对图像的相对请求只是/styles/images/

所以我的问题是处理这种情况的正确的方法是什么 ?

107537 次浏览

根据MVC4 css捆绑和图像引用上的这个线程,如果你将你的bundle定义为:

bundles.Add(new StyleBundle("~/Content/css/jquery-ui/bundle")
.Include("~/Content/css/jquery-ui/*.css"));

如果将bundle定义在与组成bundle的源文件相同的路径上,则相对映像路径仍然有效。bundle路径的最后一部分实际上是该特定bundle的file name(即/bundle可以是你喜欢的任何名称)。

这只在你将CSS从同一个文件夹中捆绑在一起时才有效(我认为从捆绑的角度来看这是有意义的)。

更新

根据下面@Hao Kung的评论,这也可以通过应用CssRewriteUrlTransformation (在绑定时更改CSS文件的相对URL引用)来实现。

注意:我还没有确认关于重写到虚拟目录中的绝对路径的问题的评论,所以这可能不适用于每个人(?)

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

另一种选择是使用IIS URL Rewrite模块将虚拟包映像文件夹映射到物理映像文件夹。下面是一个重写规则的例子,你可以将其用于名为“~/bundles/yourpage/styles”的包——注意正则表达式匹配字母数字字符以及连字符、下划线和句点,这些在图像文件名中很常见。

<rewrite>
<rules>
<rule name="Bundle Images">
<match url="^bundles/yourpage/images/([a-zA-Z0-9\-_.]+)" />
<action type="Rewrite" url="Content/css/jquery-ui/images/{R:1}" />
</rule>
</rules>
</rewrite>

这种方法产生了一些额外的开销,但是允许您对包名称有更多的控制,并且还减少了您可能必须在一个页面上引用的包的数量。当然,如果你必须引用多个包含相对图像路径引用的第三方css文件,你仍然不能绕过创建多个包。

更好的是(IMHO)实现一个自定义Bundle来修复图像路径。我为我的应用程序写了一个。

using System;
using System.Collections.Generic;
using IO = System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Optimization;

...

public class StyleImagePathBundle : Bundle
{
public StyleImagePathBundle(string virtualPath)
: base(virtualPath, new IBundleTransform[1]
{
(IBundleTransform) new CssMinify()
})
{
}


public StyleImagePathBundle(string virtualPath, string cdnPath)
: base(virtualPath, cdnPath, new IBundleTransform[1]
{
(IBundleTransform) new CssMinify()
})
{
}


public new Bundle Include(params string[] virtualPaths)
{
if (HttpContext.Current.IsDebuggingEnabled)
{
// Debugging. Bundling will not occur so act normal and no one gets hurt.
base.Include(virtualPaths.ToArray());
return this;
}


// In production mode so CSS will be bundled. Correct image paths.
var bundlePaths = new List<string>();
var svr = HttpContext.Current.Server;
foreach (var path in virtualPaths)
{
var pattern = new Regex(@"url\s*\(\s*([""']?)([^:)]+)\1\s*\)", RegexOptions.IgnoreCase);
var contents = IO.File.ReadAllText(svr.MapPath(path));
if(!pattern.IsMatch(contents))
{
bundlePaths.Add(path);
continue;
}




var bundlePath = (IO.Path.GetDirectoryName(path) ?? string.Empty).Replace(@"\", "/") + "/";
var bundleUrlPath = VirtualPathUtility.ToAbsolute(bundlePath);
var bundleFilePath = String.Format("{0}{1}.bundle{2}",
bundlePath,
IO.Path.GetFileNameWithoutExtension(path),
IO.Path.GetExtension(path));
contents = pattern.Replace(contents, "url($1" + bundleUrlPath + "$2$1)");
IO.File.WriteAllText(svr.MapPath(bundleFilePath), contents);
bundlePaths.Add(bundleFilePath);
}
base.Include(bundlePaths.ToArray());
return this;
}


}

要使用它,请执行:

bundles.Add(new StyleImagePathBundle("~/bundles/css").Include(
"~/This/Is/Some/Folder/Path/layout.css"));

...而不是……

bundles.Add(new StyleBundle("~/bundles/css").Include(
"~/This/Is/Some/Folder/Path/layout.css"));

它所做的是(当不在调试模式时)寻找url(<something>)并将其替换为url(<absolute\path\to\something>)。这是我10秒前写的,所以可能需要稍作调整。我已经考虑了完全限定的URL和base64 DataURIs,确保URL路径中没有冒号(:)。在我们的环境中,图像通常位于与其css文件相同的文件夹中,但我已经用父文件夹(url(../someFile.png))和子文件夹(url(someFolder/someFile.png)进行了测试。

咧嘴笑的方法很好。

但是,当url中有父文件夹相对引用时,它对我不起作用。 即url('../../images/car.png')

因此,我稍微改变了Include方法,以便为每个正则表达式匹配解析路径,允许相对路径,也可以选择将图像嵌入到css中。

我还将IF DEBUG更改为检查BundleTable.EnableOptimizations而不是HttpContext.Current.IsDebuggingEnabled

    public new Bundle Include(params string[] virtualPaths)
{
if (!BundleTable.EnableOptimizations)
{
// Debugging. Bundling will not occur so act normal and no one gets hurt.
base.Include(virtualPaths.ToArray());
return this;
}
var bundlePaths = new List<string>();
var server = HttpContext.Current.Server;
var pattern = new Regex(@"url\s*\(\s*([""']?)([^:)]+)\1\s*\)", RegexOptions.IgnoreCase);
foreach (var path in virtualPaths)
{
var contents = File.ReadAllText(server.MapPath(path));
var matches = pattern.Matches(contents);
// Ignore the file if no matches
if (matches.Count == 0)
{
bundlePaths.Add(path);
continue;
}
var bundlePath = (System.IO.Path.GetDirectoryName(path) ?? string.Empty).Replace(@"\", "/") + "/";
var bundleUrlPath = VirtualPathUtility.ToAbsolute(bundlePath);
var bundleFilePath = string.Format("{0}{1}.bundle{2}",
bundlePath,
System.IO.Path.GetFileNameWithoutExtension(path),
System.IO.Path.GetExtension(path));
// Transform the url (works with relative path to parent folder "../")
contents = pattern.Replace(contents, m =>
{
var relativeUrl = m.Groups[2].Value;
var urlReplace = GetUrlReplace(bundleUrlPath, relativeUrl, server);
return string.Format("url({0}{1}{0})", m.Groups[1].Value, urlReplace);
});
File.WriteAllText(server.MapPath(bundleFilePath), contents);
bundlePaths.Add(bundleFilePath);
}
base.Include(bundlePaths.ToArray());
return this;
}




private string GetUrlReplace(string bundleUrlPath, string relativeUrl, HttpServerUtility server)
{
// Return the absolute uri
Uri baseUri = new Uri("http://dummy.org");
var absoluteUrl = new Uri(new Uri(baseUri, bundleUrlPath), relativeUrl).AbsolutePath;
var localPath = server.MapPath(absoluteUrl);
if (IsEmbedEnabled && File.Exists(localPath))
{
var fi = new FileInfo(localPath);
if (fi.Length < 0x4000)
{
// Embed the image in uri
string contentType = GetContentType(fi.Extension);
if (null != contentType)
{
var base64 = Convert.ToBase64String(File.ReadAllBytes(localPath));
// Return the serialized image
return string.Format("data:{0};base64,{1}", contentType, base64);
}
}
}
// Return the absolute uri
return absoluteUrl;
}

希望能有所帮助,敬礼。

Grinn / ThePirat解决方案效果很好。

我不喜欢它的新包括方法在捆绑,并在内容目录中创建临时文件。(它们最终被检入、部署,然后服务无法启动!)

因此,为了遵循捆绑的设计,我选择执行本质上相同的代码,但在IBundleTransform实现中::

class StyleRelativePathTransform
: IBundleTransform
{
public StyleRelativePathTransform()
{
}


public void Process(BundleContext context, BundleResponse response)
{
response.Content = String.Empty;


Regex pattern = new Regex(@"url\s*\(\s*([""']?)([^:)]+)\1\s*\)", RegexOptions.IgnoreCase);
// open each of the files
foreach (FileInfo cssFileInfo in response.Files)
{
if (cssFileInfo.Exists)
{
// apply the RegEx to the file (to change relative paths)
string contents = File.ReadAllText(cssFileInfo.FullName);
MatchCollection matches = pattern.Matches(contents);
// Ignore the file if no match
if (matches.Count > 0)
{
string cssFilePath = cssFileInfo.DirectoryName;
string cssVirtualPath = context.HttpContext.RelativeFromAbsolutePath(cssFilePath);
foreach (Match match in matches)
{
// this is a path that is relative to the CSS file
string relativeToCSS = match.Groups[2].Value;
// combine the relative path to the cssAbsolute
string absoluteToUrl = Path.GetFullPath(Path.Combine(cssFilePath, relativeToCSS));


// make this server relative
string serverRelativeUrl = context.HttpContext.RelativeFromAbsolutePath(absoluteToUrl);


string quote = match.Groups[1].Value;
string replace = String.Format("url({0}{1}{0})", quote, serverRelativeUrl);
contents = contents.Replace(match.Groups[0].Value, replace);
}
}
// copy the result into the response.
response.Content = String.Format("{0}\r\n{1}", response.Content, contents);
}
}
}
}

然后将其封装在一个Bundle实现中:

public class StyleImagePathBundle
: Bundle
{
public StyleImagePathBundle(string virtualPath)
: base(virtualPath)
{
base.Transforms.Add(new StyleRelativePathTransform());
base.Transforms.Add(new CssMinify());
}


public StyleImagePathBundle(string virtualPath, string cdnPath)
: base(virtualPath, cdnPath)
{
base.Transforms.Add(new StyleRelativePathTransform());
base.Transforms.Add(new CssMinify());
}
}

示例用法:

static void RegisterBundles(BundleCollection bundles)
{
...
bundles.Add(new StyleImagePathBundle("~/bundles/Bootstrap")
.Include(
"~/Content/css/bootstrap.css",
"~/Content/css/bootstrap-responsive.css",
"~/Content/css/jquery.fancybox.css",
"~/Content/css/style.css",
"~/Content/css/error.css",
"~/Content/validation.css"
));

下面是我的RelativeFromAbsolutePath扩展方法:

   public static string RelativeFromAbsolutePath(this HttpContextBase context, string path)
{
var request = context.Request;
var applicationPath = request.PhysicalApplicationPath;
var virtualDir = request.ApplicationPath;
virtualDir = virtualDir == "/" ? virtualDir : (virtualDir + "/");
return path.Replace(applicationPath, virtualDir).Replace(@"\", "/");
}

从v1.1.0-alpha1(预发布包)开始,框架使用VirtualPathProvider来访问文件,而不是接触物理文件系统。

更新后的变压器如下所示:

public class StyleRelativePathTransform
: IBundleTransform
{
public void Process(BundleContext context, BundleResponse response)
{
Regex pattern = new Regex(@"url\s*\(\s*([""']?)([^:)]+)\1\s*\)", RegexOptions.IgnoreCase);


response.Content = string.Empty;


// open each of the files
foreach (var file in response.Files)
{
using (var reader = new StreamReader(file.Open()))
{
var contents = reader.ReadToEnd();


// apply the RegEx to the file (to change relative paths)
var matches = pattern.Matches(contents);


if (matches.Count > 0)
{
var directoryPath = VirtualPathUtility.GetDirectory(file.VirtualPath);


foreach (Match match in matches)
{
// this is a path that is relative to the CSS file
var imageRelativePath = match.Groups[2].Value;


// get the image virtual path
var imageVirtualPath = VirtualPathUtility.Combine(directoryPath, imageRelativePath);


// convert the image virtual path to absolute
var quote = match.Groups[1].Value;
var replace = String.Format("url({0}{1}{0})", quote, VirtualPathUtility.ToAbsolute(imageVirtualPath));
contents = contents.Replace(match.Groups[0].Value, replace);
}


}
// copy the result into the response.
response.Content = String.Format("{0}\r\n{1}", response.Content, contents);
}
}
}
}

这是一个Bundle Transform,它将用相对于css文件的url替换css url。只要把它添加到你的bundle中,它就会解决这个问题。

public class CssUrlTransform: IBundleTransform
{
public void Process(BundleContext context, BundleResponse response) {
Regex exp = new Regex(@"url\([^\)]+\)", RegexOptions.IgnoreCase | RegexOptions.Singleline);
foreach (FileInfo css in response.Files) {
string cssAppRelativePath = css.FullName.Replace(context.HttpContext.Request.PhysicalApplicationPath, context.HttpContext.Request.ApplicationPath).Replace(Path.DirectorySeparatorChar, '/');
string cssDir = cssAppRelativePath.Substring(0, cssAppRelativePath.LastIndexOf('/'));
response.Content = exp.Replace(response.Content, m => TransformUrl(m, cssDir));
}
}




private string TransformUrl(Match match, string cssDir) {
string url = match.Value.Substring(4, match.Length - 5).Trim('\'', '"');


if (url.StartsWith("http://") || url.StartsWith("data:image")) return match.Value;


if (!url.StartsWith("/"))
url = string.Format("{0}/{1}", cssDir, url);


return string.Format("url({0})", url);
}


}

您可以简单地向虚拟包路径添加另一个深度级别

    //Two levels deep bundle path so that paths are maintained after minification
bundles.Add(new StyleBundle("~/Content/css/css").Include("~/Content/bootstrap/bootstrap.css", "~/Content/site.css"));

这是一个超级低技术含量的答案,有点像黑客,但它确实有效,不需要任何预处理。考虑到这些答案的长度和复杂性,我更喜欢这样做。

没有必要指定转换或使用疯狂的子目录路径。经过大量的故障排除后,我将其隔离到这个“简单”规则中(这是一个bug吗?)……

如果您的包路径不是以包含的项目的相对根开始,那么web应用程序根将不会被考虑在内。

对我来说,听起来更像是一个bug,但无论如何,这就是你在当前的。net 4.51版本中修复它的方法。也许其他的答案对于旧的ASP是必要的。NET构建,不能说没有时间对所有这些进行回顾性测试。

为了澄清,这里有一个例子:

我有这些文件…

~/Content/Images/Backgrounds/Some_Background_Tile.gif
~/Content/Site.css  - references the background image relatively, i.e. background: url('Images/...')

然后像这样设置bundle…

BundleTable.Add(new StyleBundle("~/Bundles/Styles").Include("~/Content/Site.css"));

然后渲染成…

@Styles.Render("~/Bundles/Styles")

并获得“行为”(bug), CSS文件本身有应用程序根(例如。“http://localhost:1234/MySite/Content/Site.css”),但CSS图像内都开始“/Content/Images/…”或“/Images/…”,这取决于我是否添加转换。

甚至尝试创建“Bundles”文件夹,看看它是否与路径存在或不存在有关,但这并没有改变任何东西。该问题的解决方案实际上是要求包的名称必须以路径根开头。

这意味着这个例子通过像..这样注册和呈现bundle路径来修复。

BundleTable.Add(new StyleBundle("~/Content/StylesBundle").Include("~/Content/Site.css"));
...
@Styles.Render("~/Content/StylesBundle")

所以你当然可以说这是RTFM,但我很确定我和其他人从默认模板或MSDN或ASP文档的某处获取了这个“~/Bundles/…”路径。NET网站,或者只是偶然发现的,因为它实际上是一个非常符合逻辑的虚拟路径名称,选择这样的虚拟路径是有意义的,因为它与实际目录不冲突。

不管怎样,事情就是这样。微软没有发现漏洞。我不同意这一点,要么它应该像预期的那样工作,要么抛出一些异常,要么额外重写添加bundle路径,选择包含应用程序根或不包含根。我无法想象为什么有人不希望包含一个应用程序根(通常情况下,除非你安装了一个DNS别名/默认的网站根)。这应该是默认值。

我有这个问题与捆绑有不正确的路径的图像和CssRewriteUrlTransform不解决相对父路径..正确(也有外部资源的问题,如webfonts)。这就是为什么我写了这个自定义转换(似乎正确地完成了上面所有的工作):

public class CssRewriteUrlTransform2 : IItemTransform
{
public string Process(string includedVirtualPath, string input)
{
var pathParts = includedVirtualPath.Replace("~/", "/").Split('/');
pathParts = pathParts.Take(pathParts.Count() - 1).ToArray();
return Regex.Replace
(
input,
@"(url\(['""]?)((?:\/??\.\.)*)(.*?)(['""]?\))",
m =>
{
// Somehow assigning this to a variable is faster than directly returning the output
var output =
(
// Check if it's an aboslute url or base64
m.Groups[3].Value.IndexOf(':') == -1 ?
(
m.Groups[1].Value +
(
(
(
m.Groups[2].Value.Length > 0 ||
!m.Groups[3].Value.StartsWith('/')
)
) ?
string.Join("/", pathParts.Take(pathParts.Count() - m.Groups[2].Value.Count(".."))) :
""
) +
(!m.Groups[3].Value.StartsWith('/') ? "/" + m.Groups[3].Value : m.Groups[3].Value) +
m.Groups[4].Value
) :
m.Groups[0].Value
);
return output;
}
);
}
}

编辑:我没有意识到,但我在代码中使用了一些自定义扩展方法。它们的源代码是:

/// <summary>
/// Based on: http://stackoverflow.com/a/11773674
/// </summary>
public static int Count(this string source, string substring)
{
int count = 0, n = 0;


while ((n = source.IndexOf(substring, n, StringComparison.InvariantCulture)) != -1)
{
n += substring.Length;
++count;
}
return count;
}


public static bool StartsWith(this string source, char value)
{
if (source.Length == 0)
{
return false;
}
return source[0] == value;
}

当然,应该可以用String.StartsWith(string)替换String.StartsWith(char)

我发现CssRewriteUrlTransform不能运行,如果你引用一个*.css文件,你有关联的*.min.css文件在同一文件夹。

要解决这个问题,要么删除*.min.css文件,要么直接在你的bundle中引用它:

bundles.Add(new Bundle("~/bundles/bootstrap")
.Include("~/Libs/bootstrap3/css/bootstrap.min.css", new CssRewriteUrlTransform()));

在你这样做之后,你的url将被正确地转换,你的图像应该被正确地解析。

虽然Chris Baxter的回答有助于解决原始问题,但它在我的情况下并不适用当应用程序托管在虚拟目录。在研究了这些选项之后,我完成了DIY解决方案。

ProperStyleBundle类包括从原始CssRewriteUrlTransform中借来的代码,用于正确转换虚拟目录中的相对路径。如果文件不存在,它也会抛出,并阻止bundle中的文件重新排序(代码取自BetterStyleBundle)。

using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Optimization;
using System.Linq;


namespace MyNamespace
{
public class ProperStyleBundle : StyleBundle
{
public override IBundleOrderer Orderer
{
get { return new NonOrderingBundleOrderer(); }
set { throw new Exception( "Unable to override Non-Ordered bundler" ); }
}


public ProperStyleBundle( string virtualPath ) : base( virtualPath ) {}


public ProperStyleBundle( string virtualPath, string cdnPath ) : base( virtualPath, cdnPath ) {}


public override Bundle Include( params string[] virtualPaths )
{
foreach ( var virtualPath in virtualPaths ) {
this.Include( virtualPath );
}
return this;
}


public override Bundle Include( string virtualPath, params IItemTransform[] transforms )
{
var realPath = System.Web.Hosting.HostingEnvironment.MapPath( virtualPath );
if( !File.Exists( realPath ) )
{
throw new FileNotFoundException( "Virtual path not found: " + virtualPath );
}
var trans = new List<IItemTransform>( transforms ).Union( new[] { new ProperCssRewriteUrlTransform( virtualPath ) } ).ToArray();
return base.Include( virtualPath, trans );
}


// This provides files in the same order as they have been added.
private class NonOrderingBundleOrderer : IBundleOrderer
{
public IEnumerable<BundleFile> OrderFiles( BundleContext context, IEnumerable<BundleFile> files )
{
return files;
}
}


private class ProperCssRewriteUrlTransform : IItemTransform
{
private readonly string _basePath;


public ProperCssRewriteUrlTransform( string basePath )
{
_basePath = basePath.EndsWith( "/" ) ? basePath : VirtualPathUtility.GetDirectory( basePath );
}


public string Process( string includedVirtualPath, string input )
{
if ( includedVirtualPath == null ) {
throw new ArgumentNullException( "includedVirtualPath" );
}
return ConvertUrlsToAbsolute( _basePath, input );
}


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


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

StyleBundle那样使用它:

bundles.Add( new ProperStyleBundle( "~/styles/ui" )
.Include( "~/Content/Themes/cm_default/style.css" )
.Include( "~/Content/themes/custom-theme/jquery-ui-1.8.23.custom.css" )
.Include( "~/Content/DataTables-1.9.4/media/css/jquery.dataTables.css" )
.Include( "~/Content/DataTables-1.9.4/extras/TableTools/media/css/TableTools.css" ) );

也许我有偏见,但我很喜欢我的解决方案,因为它不做任何转换,正则表达式等,它有最少的代码:)

这适用于托管为IIS网站中的虚拟目录,并作为IIS上的根网站的站点

所以我创建了一个IItemTransform的实现,封装了CssRewriteUrlTransform,并使用VirtualPathUtility来修复路径并调用现有的代码:

/// <summary>
/// Is a wrapper class over CssRewriteUrlTransform to fix url's in css files for sites on IIS within Virutal Directories
/// and sites at the Root level
/// </summary>
public class CssUrlTransformWrapper : IItemTransform
{
private readonly CssRewriteUrlTransform _cssRewriteUrlTransform;


public CssUrlTransformWrapper()
{
_cssRewriteUrlTransform = new CssRewriteUrlTransform();
}


public string Process(string includedVirtualPath, string input)
{
return _cssRewriteUrlTransform.Process("~" + VirtualPathUtility.ToAbsolute(includedVirtualPath), input);
}
}




//App_Start.cs
public static void Start()
{
BundleTable.Bundles.Add(new StyleBundle("~/bundles/fontawesome")
.Include("~/content/font-awesome.css", new CssUrlTransformWrapper()));
}

似乎对我很有效?

CssRewriteUrlTransform修复了我的问题。
如果你的代码在使用CssRewriteUrlTransform后仍然没有加载图像,那么 修改你的CSS文件名:

.Include("~/Content/jquery/jquery-ui-1.10.3.custom.css", new CssRewriteUrlTransform())

:

.Include("~/Content/jquery/jquery-ui.css", new CssRewriteUrlTransform())

(点)在url中不被识别。

经过一番调查,我得出以下结论: 你有两个选项:

  1. 使用转换。这个非常有用的包:https://bundletransformer.codeplex.com/ 对于每个有问题的bundle,您需要以下转换:

    BundleResolver.Current = new CustomBundleResolver();
    var cssTransformer = new StyleTransformer();
    standardCssBundle.Transforms.Add(cssTransformer);
    bundles.Add(standardCssBundle);
    

Advantages: of this solution, you can name your bundle whatever you want => you can combine css files into one bundle from different directories. Disadvantages: You need to transform every problematic bundle

  1. Use the same relative root for the name of the bundle like where the css file is located. Advantages: there is no need for transformation. Disadvantages: You have limitation on combining css sheets from different directories into one bundle.

只需要记住在包中修复< em >多个< / em > CSS包含,例如:

bundles.Add(new StyleBundle("~/Content/styles/jquery-ui")
.Include("~/Content/css/path1/somestyle1.css", "~/Content/css/path2/somestyle2.css"));

你不能像在一个CSS文件中那样在末尾添加new CssRewriteUrlTransform(),因为该方法不支持,所以你必须多次使用Include:

bundles.Add(new StyleBundle("~/Content/styles/jquery-ui")
.Include("~/Content/css/path1/somestyle1.css", new CssRewriteUrlTransform())
.Include("~/Content/css/path2/somestyle2.css", new CssRewriteUrlTransform()));