将versionnumber附加到asp:ScriptManager的compositescript标签

时间:2010-06-09 13:57:19

标签: asp.net javascript scriptmanager

我们正在尝试使以下方案有效:

我们使用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> 

鉴于当前配置的siteversion是1.0.190,我希望它呈现

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

如何从脚本管理器获取“脚本”html输出,以便我可以更改它? 它似乎不存在于Render,RenderChildren或RenderControl

中呈现的内容中

此致 安德烈亚斯

3 个答案:

答案 0 :(得分:4)

我在反射器中挖了一下,看起来不幸的是这是一个棘手的事情。 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 :(得分:3)

在你的页面onload中一个更简单的解决方案对我来说很合适:

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

答案 2 :(得分:1)

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