让ASP.NET捆绑为CSS捆绑指定media=screen

44
我正在尝试使用ASP.NET 4.5的捆绑和缩小功能,但遇到了问题。 我有约10个CSS文件,其中2个最初使用属性media =“screen”在布局中引用。 由于添加CSS到捆绑包的语法不允许您指定应添加此类属性(因为该属性将适用于整个捆绑包),因此我希望看到@Styles.Render的重载,允许我指定HTML属性,就像其他HTML助手一样,但没有这样的方法。 有一个丑陋的解决方案,即由于我知道创建的捆绑包的URL,因此我可以自己制作标记,但这样做会失去ASP.NET处理的缓存机制,因为它允许其自己呈现标记。 是否有方法可以解决这个问题? 还是设计团队的疏忽?

只需使用@Styles.RenderFormat(请查看我的答案以获取更详细的信息) - Adam Tal
8个回答

77

我找到了一个更加优雅的解决方案。

我正在使用 Styles.RenderFormat(format, bundle)

我有一个名为 BundlesFormats 的类,其中包含一个叫做 PRINT 的属性,并且我是这样使用它的:

public class BundlesFormats
{
    public const string PRINT = @"<link href=""{0}"" rel=""stylesheet"" type=""text/css"" media=""print"" />";
}

还有在cshtml中:

@Styles.RenderFormat(BundlesFormats.PRINT, "~/bundles/Content/print")

5
请注意:此解决方案目前需要“Microsoft ASP.NET Web Optimization Framework”的预发行版本。稳定版本没有“RenderFormat”方法。 - maets
3
这现在是 1.1.0 版本的一部分。 - IvanL
5
花了我一分钟才意识到可以在一行代码中完成:@Styles.RenderFormat("<link href=""{0}"" rel=""stylesheet"" type=""text/css"" media=""print"" />", "/bundles/Content/print")。其中,该代码的作用是将定义在“/bundles/Content/print”路径下的CSS文件引入到打印媒体中。 - zacharydl
1
我认为这是最优雅的解决方案,仅代表个人意见。 - Flinkman

14

好吧,这是一个不太美观的hack,但希望团队能在下一个版本中添加一种内置的方法来完成它。

这就是我解决它的方法,保持缓存字符串并仍然能够向标签添加媒体属性。

@{
    var cssMediaBundleUrl = BundleTable.Bundles.ResolveBundleUrl("~/stylesheets/mediacss", true);
}
<link href="@cssMediaBundleUrl" rel="stylesheet" type="text/css" media="screen" />

我猜我可以把这个变成一个HTML辅助器,稍后会这样做并进行编辑。


29
你可以这样做:<link href="@Styles.Url("~/stylehseets/mediacss")" rel="stylesheet" type="text/css" media="screen" /> - Hao Kung
@GR7 升级到VS 2013 Express For Web后,这开始产生404错误。我在http://stackoverflow.com/questions/20052278/how-to-specify-media-type-for-css-bundle-in-vs-express-2013-for-web上发布了它。如何修复? - Andrus
@Andrus,你有尝试其他人发布的替代方案吗?我还没有重新审查这段代码,但希望很快会去做。 - GR7
没有,我还没有。请确认你/郝的解决方案在VS2013中不起作用,然后我会开始寻找其他方法。在这种情况下,这个答案应该被取消标记。 - Andrus

6

另一个解决此问题的选择,而不会影响调试能力,可能是:

public static IHtmlString Render(string path, IDictionary<string, object> htmlAttributes)
{
    var attributes = BuildHtmlStringFrom(htmlAttributes);

#if DEBUG
    var originalHtml = Styles.Render(path).ToHtmlString();
    string tagsWithAttributes = originalHtml.Replace("/>", attributes + "/>");
    return MvcHtmlString.Create(tagsWithAttributes);
#endif

    string tagWithAttribute = string.Format(
        "<link rel=\"stylesheet\" href=\"{0}\" type=\"text/css\"{1} />", 
        Styles.Url(path), attributes);

    return MvcHtmlString.Create(tagWithAttribute);
}
我所做的就是将给定的HTML属性附加到标签的末尾(在调试模式下),或将其附加到唯一链接标签的末尾(当启用缩小/捆绑时)。 在视图中的使用:
@Bundles.Render("~/css/print", new { media = "print" })

代码的其余部分:

public static IHtmlString Render(string path, object htmlAttributes)
{
    return Render(path, new RouteValueDictionary(htmlAttributes));
}

private static string BuildHtmlStringFrom(IEnumerable<KeyValuePair<string, object>> htmlAttributes)
{
    var builder = new StringBuilder();

    foreach (var attribute in htmlAttributes)
    {
        builder.AppendFormat(" {0}=\"{1}\"", attribute.Key, attribute.Value);
    }

    return builder.ToString();
}
我写了一篇关于这个主题的博客文章:http://danielcorreia.net/blog/quick-start-to-mvc4-bundling/

3

不幸的是,目前还没有很好的方法来钩入标签的渲染。我们考虑添加一个钩子,以便您可以添加自己的方法来渲染每个脚本/样式标签。听起来我们确实需要这样做。添加起来应该很简单,我将创建一个工作项来启用此方案...

作为一种临时解决方案,如果您愿意放弃Styles.Render给您带来的调试/发布功能,您可以使用Styles.Url渲染对捆绑包的引用,这样只会给您捆绑包的网址,您可以将其嵌入到自己的标签中。


好的,我猜你是ASP.NET团队的成员?其他Html Helpers确实有重载来允许开发人员设置HTML属性,但Bundle渲染方法却没有。我在考虑是否可以通过修改生成的标签(其中包括缓存字符串)并自己添加媒体属性来解决这个问题,这样我仍然可以享受缓存的好处,并且还能添加媒体属性。我只是觉得很奇怪这个问题竟然被团队忽略了。 - GR7
找到了一种通过框架实现的方法,虽然不太好看。稍后我会发布它。 - GR7
是的,Hao是微软优化框架的首席开发人员。 - RickAndMSFT

2

1
除非他所提到的阻塞问题已经解决,否则这是一个相关的观点。 - drzaus
1
我喜欢这种方法,因为我可以将只打印文件包含在我的主样式束中。 - zacharydl

0

Web表单解决方案

在BundleConfig.cs中:

//Print css must be a separate bundle since we are going to render it with a media=print
Bundles.Add(new StyleBundle("~/bundles/printCSS").Include("~/Content/Print.css"));

主页面:

<asp:Literal runat="server" ID="litCssPrint" />

主控页面代码文件:

litCssPrint.Text = Styles.RenderFormat(@"<link href=""{0}"" rel=""stylesheet"" type=""text/css"" media=""print"" />", "~/bundles/printCSS").ToHtmlString();

0

我进一步采纳了Adam Tal的建议。

为了可读性,我可能有点过度编码,但我创建了一个静态类来模拟Styles.Render格式。

public static class StyleExtensions
{
    public enum Format
    {
        Async,
        Preload,
    }

    public static IHtmlString Render(string contentPath, Format format)
    {
        switch (format)
        {
            case Format.Async:
            return contentPath.ToAsyncFormat();
            case Format.Preload:
            return contentPath.ToPreloadFormat();
            default:
            return new HtmlString(string.Empty);
        }
    }

    public static IHtmlString RenderAsync(string contentPath)
    {
        return contentPath.ToAsyncFormat();
    }

    public static IHtmlString RenderPreload(string contentPath)
    {
        return contentPath.ToPreloadFormat();
    }

    public static IHtmlString ToAsyncFormat(this string contentPath)
    {
        return Styles.RenderFormat("<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}\" media=\"print\" onload=\"this.media='all';this.onload=null;\">", contentPath);
    }

    public static IHtmlString ToPreloadFormat(this string contentPath)
    {
        return Styles.RenderFormat("<link rel=\"preload\" href=\"{0}\" as=\"style\" onload=\"this.rel='stylesheet';this.onload=null;\">", contentPath);
    }
}

我可能会删除直接构造函数或枚举构造函数,你也可以将字符串扩展放在方法内部,具体取决于哪种方式更有意义,但你需要相应地调用以下任一方式:

@StyleExtensions.Render("~/Content/bundle-bootstrap", StyleExtensions.Format.Preload)
@StyleExtensions.Render("https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;700&display=swap", StyleExtensions.Format.Preload)
@StyleExtensions.Render(Url.Content("~/Content/Styles/Primary.min.css"), StyleExtensions.Format.Async)

或者

@StyleExtensions.RenderPreload("~/Content/bundle-bootstrap")
@StyleExtensions.RenderPreload("https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;700&display=swap")
@StyleExtensions.RenderAsync(Url.Content("~/Content/Styles/Primary.min.css"))

-1

这么复杂,为什么不使用:

bundles.Add<StylesheetBundle>("~/Css/site.css", b => b.Media = "screen");

?


1
这里使用的是哪个软件包版本?Microsoft.AspNet.Web.Optimization.1.1.3不包含通用的Add方法。 - janv8000
这些东西来自哪里?Add<T>()StylesheetBundle - SandRock

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,