297

我的问题与此类似:

ASP.NET MVC 4 缩小和背景图像

除了如果可以的话,我想坚持使用 MVC 自己的捆绑。我想弄清楚指定样式包的正确模式是什么,以便独立的 css 和图像集(如 jQuery UI)工作,我陷入了大脑崩溃。

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

据我了解,当我指定 a 时,StyleBundle我需要指定一个与真实内容路径不匹配的虚拟路径,因为(假设我忽略了到 Content 的路由)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/.

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

4

16 回答 16

363

根据这个关于MVC4 css bundling and image references的线程,如果你将你的包定义为:

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

如果您在与组成包的源文件相同的路径上定义包,则相对图像路径仍然有效。捆绑包路径的最后一部分实际上是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()));
于 2012-07-08T21:47:21.900 回答
34

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

我不喜欢它在 bundle 上新增了 Include 方法,并且它在内容目录中创建了临时文件。(他们最终被签入、部署,然后服务无法启动!)

因此,为了遵循 Bundling 的设计,我选择执行基本相同的代码,但在 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(@"\", "/");
    }
于 2012-10-22T20:30:03.160 回答
20

更好的是(恕我直言)实现了一个修复图像路径的自定义 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 路径中没有冒号 (:),我考虑了完全限定的 URL 和 base64 DataURI。在我们的环境中,图像通常与它们的 css 文件位于同一个文件夹中,但我已经使用父文件夹 ( url(../someFile.png)) 和子文件夹 ( url(someFolder/someFile.png) 对其进行了测试。

于 2012-10-02T18:41:30.330 回答
13

没有必要指定转换或具有疯狂的子目录路径。经过多次故障排除后,我将其隔离为这个“简单”规则(这是一个错误吗?)......

如果您的包路径不是以所包含项目的相对根目录开头,则不会考虑 Web 应用程序根目录。

听起来对我来说更像是一个错误,但无论如何,这就是您使用当前 .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/...')

然后像...一样设置捆绑包

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

并将其渲染为...

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

并获得“行为”(错误),CSS 文件本身具有应用程序根目录(例如“http://localhost:1234/MySite/Content/Site.css”),但其中的 CSS 图像都以“/Content/Images”开头/..." 或 "/Images/..." 取决于我是否添加了转换。

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

这意味着这个例子是通过注册和渲染捆绑路径来修复的,比如..

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

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

无论如何,就是这样。微软没有看到任何错误。我不同意这一点,要么它应该按预期工作,要么应该抛出一些异常,或者额外覆盖添加选择包含应用程序根目录的捆绑路径。我无法想象为什么有人不希望包含应用程序根目录(通常除非您使用 DNS 别名/默认网站根目录安装您的网站)。所以实际上这应该是默认值。

于 2014-06-12T16:37:36.287 回答
12

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

这适用于作为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()));
}

对我来说似乎工作得很好?

于 2015-06-16T14:46:37.093 回答
11

我发现如果您引用一个文件并且在同一文件夹中*.css有关联的文件,则 CssRewriteUrlTransform 无法运行。*.min.css

要解决此问题,请删除该*.min.css文件或直接在您的包中引用它:

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

之后,您的 URL 将被正确转换,并且您的图像应该被正确解析。

于 2014-12-12T00:18:42.753 回答
7

尽管 Chris Baxter 的回答有助于解决原始问题,但在我的情况下,当应用程序托管在 virtual directory 时它不起作用。在研究了这些选项后,我完成了 DIY 解决方案。

ProperStyleBundle类包括从原始借用的代码,CssRewriteUrlTransform以正确转换虚拟目录中的相对路径。如果文件不存在,它也会抛出并阻止重新排序包中的文件(代码取自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" ) );
于 2015-01-11T19:03:27.503 回答
6

从 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);
            }
        }
    }
}
于 2012-11-30T12:04:55.740 回答
5

这是一个捆绑转换,它将用相对于该 css 文件的 url 替换 css url。只需将其添加到您的捆绑包中,它应该可以解决问题。

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);
    }

}
于 2013-03-26T13:00:29.303 回答
4

另一种选择是使用 IIS URL 重写模块将虚拟包映像文件夹映射到物理映像文件夹。下面是一个重写规则的示例,您可以将其用于名为“~/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>

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

于 2012-09-12T19:54:33.713 回答
4

格林解决方案很棒。

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

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

我还将 IF DEBUG 更改为 checkBundleTable.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;
    }

希望它有帮助,问候。

于 2012-10-19T23:03:18.567 回答
2

您可以简单地为您的虚拟捆绑路径添加另一个层次的深度

    //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"));

这是一个超低技术含量的答案,有点像 hack,但它可以工作,不需要任何预处理。鉴于其中一些答案的长度和复杂性,我更喜欢这样做。

于 2013-12-23T21:21:18.467 回答
2

我遇到了这个问题,捆绑包的图像路径不正确并且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(char)String.StartsWith(string).

于 2014-11-05T13:45:53.723 回答
1

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

  1. 进行转换。对此非常有用的软件包:https ://bundletransformer.codeplex.com/ 您需要对每个有问题的捆绑包进行以下转换:

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

优点:在此解决方案中,您可以随意命名您的包 => 您可以将不同目录中的 css 文件组合成一个包。缺点:您需要转换每个有问题的捆绑包

  1. 对包的名称使用相同的相对根目录,例如 css 文件所在的位置。优点:无需改造。缺点:您在将不同目录中的 css 表单组合成一个包时受到限制。
于 2016-01-07T20:29:39.837 回答
0

CssRewriteUrlTransform解决了我的问题。
如果您的代码在使用后仍未加载图像CssRewriteUrlTransform,则将您的 css 文件名更改为:

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

到:

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

不知何故。(点)在网址中无法识别。

于 2015-09-10T08:23:09.273 回答
0

只需记住修复捆绑包中的多个CSS 包含项,例如:

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

您不能new CssRewriteUrlTransform()像使用一个 CSS 文件一样添加到末尾,因为该方法不支持它,因此您必须多次使用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()));
于 2020-05-22T08:53:11.880 回答