构建事件和版本控制.js和.css文件

时间:2009-10-02 17:06:48

标签: msbuild versioning

我设置了一个MSBuild脚本来缩小和组合我的javascript和css文件。我现在需要的是一种版本化的方法。你们现在如何处理这个问题。增量版本文件并使用新文件名更新<script/>标记的最佳方法是什么?

1 个答案:

答案 0 :(得分:0)

我原本打算建议使用资源表达式来包含来自AppSettings的版本标记,但是经过测试发现它只有在服务器控件属性的整个值时才有效。

每个版本的构建脚本都可以更新AppSettings值;可以是你喜欢的任何格式:

<appSettings>
 <add key="versionTag" value="27" />
</appSettings>

使用:

<asp:Label runat="server" Text="<%$ AppSettings: versionTag %>" />

不起作用:

<link runat="server" rel="Stylesheet" type="text/css"
      href='/css/site.css?v=<%$ AppSettings: versionTag %>' />

所以我的实际建议是创建自己的控件来读取版本标签并将其包含在输出中。以下是我的CSS控件在页面上的显示方式(注意:服务器控件必须位于服务器端表单内,即使它可能在head元素内部呈现):

...
<form id="form1" runat="server">
 <my:Stylesheet runat="server" Url="~/css/site.css" />
</form>
...

我的样式表控件的代码:

namespace MyNamespace
{
    using System;
    using System.ComponentModel;
    using System.Configuration;
    using System.Security.Permissions;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.HtmlControls;
    using System.Web.UI.WebControls;

    /// <summary>
    /// Outputs a CSS stylesheet link that supports versionable caching via a
    /// build-specific query parameter.
    /// </summary>
    [
        AspNetHostingPermission(SecurityAction.InheritanceDemand,
                Level = AspNetHostingPermissionLevel.Minimal),
        AspNetHostingPermission(SecurityAction.LinkDemand,
                Level = AspNetHostingPermissionLevel.Minimal),
        DefaultProperty("Href"),
        ToolboxData(@"<{0}:Stylesheet runat=""server"" />")
    ]
    public class Stylesheet : WebControl
    {
        private static string versionTag = Stylesheet.GetVersionTag();

        /// <summary>
        /// Gets or sets the stylesheet URL.
        /// </summary>
        public string Href
        {
            get
            {
                return this.ViewState["Href"] as string;
            }

            set
            {
                this.ViewState["Href"] = value;
            }
        }

        /// <summary>
        /// Raises the PreRender event.
        /// </summary>
        /// <param name="e">Contains the event data.</param>
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            HtmlLink link = new HtmlLink();
            link.Href = String.Format(
                    "{0}?v={1}",
                    this.Page.ResolveUrl(this.Href),
                    HttpUtility.UrlEncode(Stylesheet.versionTag));

            if (!Stylesheet.HeadContainsLinkHref(this.Page, link.Href))
            {
                link.Attributes["type"] = "text/css";
                link.Attributes["rel"] = "Stylesheet";
                this.Page.Header.Controls.Add(link);
            }
        }

        /// <summary>
        /// Generates content to be rendered on the client.
        /// </summary>
        /// <param name="writer">Receives the server control content.</param>
        protected override void Render(HtmlTextWriter writer)
        {
            // Do nothing.
        }

        /// <summary>
        /// Retrieves the script version tag for this build.
        /// </summary>
        /// <returns>Returns the script version tag.</returns>
        private static string GetVersionTag()
        {
            string tag = ConfigurationManager.AppSettings["versionTag"];
            if (String.IsNullOrEmpty(tag))
            {
                tag = "1";
            }

            return tag;
        }

        /// <summary>
        /// Determines if the page's <c>head</c> contains a <c>link</c> tag
        /// with a matching <c>href</c> attribute value.
        /// </summary>
        /// <param name="thePage">The Page to be tested.</param>
        /// <param name="href">The <c>href</c> URL to be matched.</param>
        /// <returns>Returns true if a matching link is already part of the
        /// page <c>head</c> or false otherwise.</returns>
        public static bool HeadContainsLinkHref(Page thePage, string href)
        {
            if (thePage == null)
            {
                throw new ArgumentNullException("thePage");
            }

            foreach (Control control in thePage.Header.Controls)
            {
                if ((control is HtmlLink) &&
                    (control as HtmlLink).Href == href)
                {
                    return true;
                }
            }

            return false;
        }
    }
}

HTH。