【问题标题】:append versionnumber to asp:ScriptManager's compositescript tag将版本号附加到 asp:ScriptManager 的复合脚本标签
【发布时间】:2010-06-09 13:57:19
【问题描述】:

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

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

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

<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> 

如何从脚本管理器获取“脚本”html 输出,以便进行更改? 它似乎不存在于 Render、RenderChildren 或 RenderControl 中呈现的内容中

你的 安德烈亚斯

【问题讨论】:

  • -1 你打开了一个赏金,你甚至没有选择一个答案,即使有工作!态度很差。

标签: asp.net javascript scriptmanager


【解决方案1】:

我在反射器中挖了一会儿,不幸的是,这似乎是一件棘手的事情。 MS 没有提供我能找到的任何好的扩展点。但是,如果您愿意使用一个不错的反射技巧,那么为 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>

我对此进行了测试,它对我有用。希望对你有帮助。

【讨论】:

  • +1 安迪我投票给你的答案,因为它更接近问题,而且如果安德烈亚斯忘记选择一个,最好有人得到赏金。
  • 不知何故,我的 Web.browser sn-p 没有进入我的原始帖子。下面是它的样子: 浏览器>
  • 这段代码终于不工作了!我认为它需要更多的工作和测试。
  • 您确认控制适配器配置了吗?尝试在适配器的 OnPreRender 方法中设置断点并验证调试器是否命中断点。如果没有,则表示您的 .browser 文件配置不正确。 .browser 文件需要位于您网站的 App_Browsers 文件夹中...
【解决方案2】:

页面加载中的一个更简单的解决方案对我来说效果很好:

ScriptManager.GetCurrent(this).CompositeScript.Path += "?v=" + MyBuildNumber.Value;

【讨论】:

    【解决方案3】:

    我会建议一个不同的 aproche。 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);
            }
        }
    }
    

    【讨论】:

    • 这种方法的问题在于,浏览器最终会在网络服务器上进行大量不必要的往返,结果却发现文件自上次以来没有被修改过。在一个重要的网站上,这可能会对网站的性能产生重大影响(往返 = 糟糕)。使用版本化 url 的优点是您可以非常积极地缓存脚本,并且仅在脚本更新时(通过增加版本号)强制浏览器进行往返。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-08
    • 1970-01-01
    • 2022-01-14
    相关资源
    最近更新 更多