7

次のシナリオを機能させようとしています。

asp:scriptmanager / CompositeScriptsを使用してスクリプトをいくつかのスクリプトブロックに結合しますが、テストシステムにデプロイするたびに、テスターがcssとjavascript(ブラウザーキャッシュ)の更新バージョンを取得できないという問題が発生します。CSSの場合、たとえばcssurlにSiteversionパラメーター「?v=1.0.190」を追加する独自のcssユーザーコントロールを定義しました。このサイトバージョンはweb.config/appsettingsで定義されており、デプロイごとにバンプされます。

JavaScriptにも同じ戦略を使用できるようにしたかったのですが、これまでのところ成功していません。スクリプトタグをレンダリングするとき。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> 

スクリプトマネージャからの「script」html出力を取得して変更できるようにするにはどうすればよいですか?Render、RenderChildren、またはRenderControlでレンダリングされたものには存在しないようです

あなたのアンドレアス

4

3 に答える 3

4

リフレクターを少し掘り下げましたが、残念ながらこれを追加するのは難しいようです。MSは私が見つけることができる良い拡張ポイントを提供しませんでした。ただし、優れたリフレクションハックを使用する場合は、次のControlAdapterforScriptManagerを追加することでうまくいくはずです。

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ファイルを作成し、それをWebサイトのApp_Browsersフォルダーに配置する必要があります。Web.browserファイルは次のようになります。

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

私はこれをテストしました、そしてそれは私のために働きました。お役に立てば幸いです。

于 2010-06-17T05:22:24.900 に答える
3

ページのonloadのはるかに単純なソリューションは、私にとっては問題なく機能します。

ScriptManager.GetCurrent(this).CompositeScript.Path += "?v=" + MyBuildNumber.Value;
于 2011-01-19T00:30:08.930 に答える
1

別のアプローチを提案します。チャッシュが問題です。次に、キャッシュヘッダーを変更します。これは私がそれを作ってテストした例であり、それはうまく機能します。通話開始時の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);
        }
    }
}
于 2010-06-14T14:03:02.127 に答える