我的问题与此类似:

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

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

我有一个典型的MVC网站结构与/Content/css包含我的基本css,如样式。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/。

所以我的问题是,怎样处理这种情况才是正确的?


当前回答

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

使用转换。非常有用的包:https://bundletransformer.codeplex.com/ 对于每个有问题的bundle,你需要以下转换: BundleResolver。Current = new CustomBundleResolver(); var cssTransformer = new StyleTransformer(); standardCssBundle.Transforms.Add (cssTransformer); bundles.Add (standardCssBundle);

优点:在这个解决方案中,你可以将你的包命名为任何你想要的名称=>,你可以将css文件从不同的目录组合到一个包中。 缺点:你需要转换每个有问题的捆绑包

使用相同的相对根作为包的名称,比如css文件所在的位置。优点:不需要转换。 缺点:在将来自不同目录的css表合并到一个bundle时受到限制。

其他回答

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

根据MVC4 css bundle和图片引用的这个线程,如果你定义你的bundle为:

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

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

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

更新

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

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

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

只需要记住在一个包中修复多个CSS包含,例如:

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

你不能只添加新的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()));

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

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

似乎对我很有效?

另一种选择是使用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文件,你仍然不能绕过创建多个包。