代码之家  ›  专栏  ›  技术社区  ›  AndreasKnudsen

将versionNumber附加到asp:scriptmanager的computescript标记

  •  7
  • AndreasKnudsen  · 技术社区  · 14 年前

    我们正在尝试使以下场景工作:

    我们使用asp:scriptmanager/compositescripts将我们的脚本组合成几个脚本块,但是在每次部署到测试系统之后,我们都会遇到测试人员无法获取CSS和javascript(浏览器缓存)的更新版本的问题。对于CSS,我们已经定义了自己的CSS用户控件,它附加了SiteVersion参数“”。v=1.0.190”,例如CSS URL。此站点版本在web.config/appsettings中定义,并在每次部署时被缓冲。

    我们希望能够对javascripts使用相同的策略,但到目前为止,我还没有取得任何成功。 呈现脚本标记时。脚本管理器呈现

    <script src="/ScriptResource.axd?d=..." type="text/javascript"></script> 
    

    鉴于当前配置的站点版本是1.0.190,我希望它

    <script src="/ScriptResource.axd?d=...&v=1.0.190" type="text/javascript"></script> 
    

    如何从脚本管理器获取“script”HTML输出,以便更改它? 它似乎不存在于渲染、renderchildren或rendercontrol中渲染的内容中。

    你的 安德烈亚斯

    3 回复  |  直到 7 年前
        1
  •  3
  •   Chris    14 年前

    在您页面的onload中有一个更简单的解决方案对我来说很好:

    ScriptManager.GetCurrent(this).CompositeScript.Path += "?v=" + MyBuildNumber.Value;
    
        2
  •  4
  •   nZeus    9 年前

    我在反射镜里挖了一会儿,看起来很不幸这是一个棘手的问题。微软没有提供我能找到的任何好的扩展点。但是,如果您愿意使用一个不错的反射黑客,那么为scriptmanager添加以下ControlAdapter应该可以做到这一点:

    public class VersionedScriptManagerAdapter : ControlAdapter
    {
        protected new ScriptManager Control
        {
            get { return (ScriptManager) base.Control; }
        }
    
        protected override void OnPreRender(System.EventArgs e)
        {
            base.OnPreRender(e);
    
            var compositeScriptField = Control.GetType().GetField("_compositeScript",
                                                                  BindingFlags.NonPublic | BindingFlags.Instance);
            var currentCompositeScript = Control.CompositeScript;
            var versionedCompositeScript = new VersionedCompositeScriptReference();
            CopyCompositeScript(currentCompositeScript, versionedCompositeScript);
            compositeScriptField.SetValue(Control, versionedCompositeScript);
        }
    
        private void CopyCompositeScript(CompositeScriptReference sourceCompositeScript, CompositeScriptReference targetCompositeScript)
        {
            targetCompositeScript.Path = sourceCompositeScript.Path;
            targetCompositeScript.ResourceUICultures = sourceCompositeScript.ResourceUICultures;
            targetCompositeScript.ScriptMode = sourceCompositeScript.ScriptMode;
            foreach (var scriptReference in sourceCompositeScript.Scripts)
            {
                targetCompositeScript.Scripts.Add(scriptReference);
            }
        }
    
        private class VersionedCompositeScriptReference : CompositeScriptReference
        {
            protected override string GetUrl(ScriptManager scriptManager, bool zip)
            {
                string version = ConfigurationManager.AppSettings["ScriptVersion"];
                return base.GetUrl(scriptManager, zip) + "&v=" + version;
            }
        }
    }
    

    然后要连接这个控制适配器,您需要创建一个web.browser文件,并将其放在网站上的app_browsers文件夹中。web.browser文件应该如下所示:

    <browsers>
        <browser refID="Default">
          <controlAdapters>
            <adapter controlType="System.Web.UI.ScriptManager"
              adapterType="MyNamespace.VersionedScriptManagerAdapter">
            </adapter>
          </controlAdapters>
        </browser>
    </browsers>
    

    我测试过这个,它对我有用。我希望它对你有帮助。

        3
  •  1
  •   Aristos    14 年前

    我建议穿一条不同的围裙。Chache是您的问题,然后更改缓存头。 这里有一个例子,我做了测试,它的工作很好。在global.asax上,在呼叫的开始…

    protected void Application_BeginRequest(Object sender, EventArgs e)
    {
        HttpApplication app = (HttpApplication)sender;
    
        string cTheFile = HttpContext.Current.Request.Path;
    
        if (cTheFile.EndsWith("ScriptResource.axd", StringComparison.InvariantCultureIgnoreCase))
        {
            // here is the trick with your version !
            string etag = "\"" + app.Context.Request.QueryString.ToString().GetHashCode().ToString() + "1.0.190" + "\"";
            string incomingEtag = app.Request.Headers["If-None-Match"];
    
            app.Response.Cache.SetETag(etag);
    
            if (String.Compare(incomingEtag, etag) == 0)
            {
                app.Response.StatusCode = (int)System.Net.HttpStatusCode.NotModified;
                app.Response.StatusDescription = "Not Modified";                            
            }
            else
            {
                app.Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(1));
                app.Response.Cache.SetMaxAge(new TimeSpan(0, 1, 0));
                app.Response.Cache.SetCacheability(HttpCacheability.Public);
            }
        }
    }