ASP.NET CssMinify,HttpContextBase

时间:2014-01-21 21:02:41

标签: asp.net css asp.net-mvc asp.net-mvc-4 minify

我有一个ASP.NET应用程序需要有多个视图布局。有一个普通的Web布局,以及一个没有依赖关系的自包含页面的“静态”布局(用作文档管理系统中的显示模板)。

让视图切换其布局很容易。

因此,一体化页面布局需要将所有CSS包含在页面内的<style>标记中。我找到了一种方法来找出捆绑包中的文件,并编写了一个类似的方法:

@MyCode.IncludeCSS("~/StaticLayout/css")

它读取包中的CSS文件,并将其内容发布到<style>标记内的页面中。

但我想缩小CSS。

我无法找到System.Web.Optimization.CssMinify的任何文档。您需要调用Process方法,该方法需要BundleContext。那么......找一个,创造一个? MSDN isn't much use

public BundleContext(
    HttpContextBase context,
    BundleCollection collection,
    string bundleVirtualPath
)

Parameters
    context
        Type: System.Web.HttpContextBase
        The context.

嗯,这绝对有用。我无法知道context(类型语境)是背景,直到雷德蒙德的一些脑筋发达的脑力激荡从他忙碌的午睡中抽出一些时间用他的面前推出一篇明确的文章。肥胖的小爪子在一阵温暖的流口水中散发出来之前。

尽管如此,我仍然不知道它是什么,或者你从哪里得到它,谷歌也不知道。 HttpContext.Current不是从它派生的,也没有属性(我能找到)。

This page有一些关于正常捆绑的好信息,但它假设框架将以传统方式捆绑和提供捆绑内容,作为单独请求的资源。

有人这样做过吗?

1 个答案:

答案 0 :(得分:1)

Ed Plunkett,

如果您将其用作HTML帮助程序,则可以从HttpContextBase属性中获取ViewContext.HttpContext。这可以创建,例如。

public static IHtmlString BundleCss(this HtmlHelper html, string outputPath, params string[] cssFilePaths)
{
    var collection = new BundleCollection();
    foreach (var cssFilePath in cssFilePaths)
        collection.Add(new Bundle(cssFilePath));

    var bundler = new BundleContext(html.ViewContext.HttpContext, collection, outputPath);
    //... ommitted code
    System.Web.Optimization.CssMinify minify = new CssMinify();
    minify.Process(bundler, response);
    //... TODO: Grab the response content and return
}

是的,这是使用HTML帮助程序的基本示例。如果这不能回答你的问题,请告诉我。

编辑:重新阅读问题后,我正在澄清我的回复。所以上面的内容有助于从问题中找到HttpContextBase属性。但是我认为问题是如何实际阅读文件内容,缩小文件并将其放入页面上的<style>标签。

我写了自己对你的要求的解释,并提出了以下一组课程

我的CssOutputBundler类:

public class CssOutputBundler
{
    static readonly Dictionary<string, string> cachedOutput = new Dictionary<string, string>();
    readonly string tempFileOutputPath;
    readonly HtmlHelper helper;
    readonly IList<string> virtualFilePaths;

    public CssOutputBundler(HtmlHelper helper, string tempFileOutputPath)
    {
        if (helper == null)
            throw new ArgumentNullException("helper null");
        if (string.IsNullOrWhiteSpace(tempFileOutputPath))
            this.tempFileOutputPath = tempFileOutputPath;
        this.helper = helper;
        this.virtualFilePaths = new List<string>();
        this.tempFileOutputPath = tempFileOutputPath;
    }

    public CssOutputBundler Add(string cssFilePath)
    {
        if (!this.virtualFilePaths.Contains(cssFilePath))
            this.virtualFilePaths.Add(cssFilePath);
        return this;
    }

    public IHtmlString Minify()
    {
        if (helper == null)
            throw new ArgumentNullException("helper null");

        string cache_string = string.Join(",", this.virtualFilePaths);
        if(cachedOutput.ContainsKey(cache_string))
            return formatResponse(File.ReadAllText(cachedOutput[cache_string]));
        var bundle = new StyleBundle(this.tempFileOutputPath).Include(this.virtualFilePaths.ToArray());
        var collection = new BundleCollection();
        collection.Add(bundle);
        var context = new BundleContext(helper.ViewContext.HttpContext, collection, "");
        var response = bundle.GenerateBundleResponse(context);
        System.Web.Optimization.CssMinify minify = new CssMinify();
        minify.Process(context, response);
        string serverPath = helper.ViewContext.HttpContext.Server.MapPath(this.tempFileOutputPath);
        string outputPath = Guid.NewGuid().ToString() + ".css";
        while(File.Exists(Path.Combine(serverPath, outputPath)))
            outputPath = Guid.NewGuid().ToString() + ".css";

        File.WriteAllText(outputPath, response.Content);
        cachedOutput[cache_string] = outputPath;
        return formatResponse(response.Content);
    }

    IHtmlString formatResponse(string responseContent)
    {
        StringBuilder responseBuilder = new StringBuilder();
        responseBuilder.AppendLine("<style type=\"text/css\">");
        responseBuilder.Append(responseContent);
        responseBuilder.AppendLine("</style>");
        return helper.Raw(responseBuilder.ToString());
    }
}

好的,上面的类看起来很复杂,但它只是创建了一个内部路径列表,供捆绑器捆绑和缩小。调用Minify方法时,它会将虚拟路径格式化为一个字符串,该字符串用作缓存键。这就是我们如何确定是否已经捆绑和缩小这些脚本的方法。

如果我们读取存储在HDD上的临时捆绑脚本。

注意: 我使用的是硬盘存储,而不是内存存储。这可以通过将完整内容填充到静态字典或其他缓存介质中来轻松更改。

如果此文件集尚未捆绑,缩小等,则我们继续捆绑并缩小集合。最后,我们将文件存储到HDD上并返回响应。所以这很容易。

现在要实现这个类,我刚刚写了一个快速的HTML Helper,因为Minification类支持链接Add文件,方法可以很好地实现。

HTML帮助程序:

public static CssOutputBundler BundleCss(this HtmlHelper helper, string outputVirtualPath)
{
    return new CssOutputBundler(helper, outputVirtualPath);
}

确定捆绑器的基本实现。现在这个帮助器获取字符串outputVirtualPath这是存储临时文件的虚拟PATH。如果您决定取消保存到HDD并使用缓存系统,则可以从帮助程序和类中删除此参数。

最后,这可以在您的视图中用作......

@Html.BundleCss("~/Content/").Add("~/Content/Site.css").Add("~/Content/themes/base/jquery-ui.css").Minify();

~/Content/是HDD上用于存储缩小文件的虚拟路径。然后我们添加两个文件"~/Content/Site.css"~/Content/themes/base/jquery-ui.css。最后调用minify方法返回html字符串。比如...

<style type="text/css">
.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)} ....more css
</style>

干杯。