ASP.NET ScriptManager 输出未包含在 ASP.NET 部分缓存 (ascx) 中

发布于 2024-09-26 15:45:48 字数 18232 浏览 0 评论 0原文

我编写了一个简单控件,它实现了 ScriptControl。这是 JQuery 框架的持有者:

 /// <summary>
/// Generic control with client behavior handled via jQuery
/// </summary>
public abstract partial class JQControl : ScriptControl, INamingContainer
{
    /// <summary>
    /// Client method to be called after jQuery initialization
    /// </summary>
    [PersistenceMode(PersistenceMode.InnerProperty)]
    public JQRaw AfterInit
    {
        get;
        set;
    }

    /// <summary>
    /// Client method to be called before jQuery initialization
    /// </summary>
    [PersistenceMode(PersistenceMode.InnerProperty)]
    public JQRaw PreInit
    {
        get;
        set;
    }

    /// <summary>
    /// Any data to initialize the control with (name-value pairs)
    /// </summary>
    public IDictionary<string, object> InitData
    {
        get; set;
    }

    /// <summary>
    /// Authorization templates to be registered and used by privilege manager
    /// </summary>
    public IDictionary<string, AuthorizationTemplate> AuthorizationTemplates
    {
        get; set;
    }

    /// <summary>
    /// If ThemePath is specified, this css file will be looked for and loaded from the theme folder
    /// </summary>
    protected string ThemeCssName
    {
        get; set;
    }

    private string _themePath;

    /// <summary>
    /// Specifies path to look for custom css and images to enable theming.
    /// </summary>
    public string ThemePath
    {
        get
        {
            return _themePath == null ? DefaultThemeHelper.ThemeName : ResolveClientUrl(_themePath);
        }
        set
        {
            _themePath = value;
        }
    }

    /// <summary>
    /// Collection of streamed javascript files
    /// </summary>
    private readonly List<ScriptReference> scriptRefs = new List<ScriptReference>();

    /// <summary>
    /// Collection of streamed stylesheet files
    /// </summary>
    private readonly List<string> cssRefs = new List<string>();

    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
        FillScriptReferences();
    }

    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);

    }
    protected bool useDynamicCss = true;




    private bool dynamicCssEnabled;
    protected void EnableDynamicCss()
    {
        if(!dynamicCssEnabled)
        {
            //enable dynamic css loading
            addScriptReference(typeof(JQControl), "LWM.Implementation.Controls.DynamicStylesheet.css.js");
            dynamicCssEnabled = true;
        }
    }

    protected virtual void FillScriptReferences()
    {
        Type t = typeof(JQControl);
        addScriptReference(t, "LWM.Implementation.Controls.JScripts.Jquery.js");
        addScriptReference(t, "LWM.Implementation.Controls.JScripts.ExtendJQuery.js");
        addScriptReference(t, "LWM.Implementation.Controls.JScripts.ExtendAJAXDotNet.js");
        addScriptReference(t, "LWM.Implementation.Controls.JQ.ChainRequests.js");
        addScriptReference(t, "LWM.Implementation.Controls.JScripts.jquery.jcache.js");
        addScriptReference(t, "LWM.Implementation.Controls.JScripts.jquery.cookie.js");
        addScriptReference(t, "LWM.Implementation.Controls.JScripts.jquery.offset.js");
        //if ((_themePath != null && ThemeCssName != null))
        {
            EnableDynamicCss();                
        }
    }

    //added to render automatically assigned id, otherwise escaped
    protected override void AddAttributesToRender(HtmlTextWriter writer)
    {
        const string extCss = "jqcontrol";
        this.CssClass = this.CssClass != null ? this.CssClass + " " + extCss : extCss;

        base.AddAttributesToRender(writer);
        writer.AddAttribute(HtmlTextWriterAttribute.Id, ClientID);
        //writer.AddAttribute(HtmlTextWriterAttribute.Class, CssClass);
    }

    /// <summary>
    /// Ataches an embedded script refernnce using its full name
    /// </summary>
    /// <param name="name">Name of the reference</param>
    /// <param name="useBaseClassAssembly">True if using base class assembly</param>
    protected void AttachScriptRefernceByName(string name, bool useBaseClassAssembly)
    {
        //current type
        Type type = this.GetType();
        if (useBaseClassAssembly)
        {
            //base type
            type = type.BaseType;
        }
        addScriptReference(type, name);
    }

    private void _addCssReference(Type type, string name)
    {
        string assembly = type.Assembly.FullName;
        Type t = null;
        if (BoostHelper.AdjustResourceParts(this, type.Assembly, ref assembly, ref name, ref t))
        {
           //  LoggerHelper.LogInfo(String.Format("CSS init with- Client Script:{0}, Type:{1}, Name:{2} ", this.Page.ClientScript.ToString(),t.ToString(),name),"LWMSiteResourceBooster");

            var sr = new DynamicStylesheetScriptReference(this.Page.ClientScript, t, new[] { name });    //(name, assembly);

            if (!scriptRefs.Contains(sr))
            {
                scriptRefs.Add(sr);
            }
        }
        else
        {
            string url = name;  // GetEmbeddedURL(type, name);
            if (!cssRefs.Contains(url))
            {
                cssRefs.Add(url);
            }
        }
    }

    //protected void addCssReference(string name, Type type)
    //{
    //    _addCssReference(type, name);
    //    if (cssRefs.Count > 0)
    //    {
    //        scriptRefs.Add(new DynamicStylesheetScriptReference(this.Page.ClientScript, type, cssRefs.ToArray()));
    //        cssRefs.Clear();
    //    }
    //}

    protected void addCssReference(Type type, params string[] names)
    {
        if (names == null) return;
        foreach (string name in names)
        {
            _addCssReference(type, name);
        }
        if(cssRefs.Count > 0)
        {
            scriptRefs.Add(new DynamicStylesheetScriptReference(this.Page.ClientScript, type, cssRefs.ToArray()));
            cssRefs.Clear();
        }
    }


    protected void removeCssReference(Type type, string name)
    {
        //TODO
        //if (cssRefs.Contains(url))
        //{
        //    cssRefs.Remove(url);
        //}
    }

    protected void addScriptReference(Type type, string name)
    {


        //full name of the current assembly            
        string assembly = type.Assembly.FullName;
        Type t = null;
        BoostHelper.AdjustResourceParts(this, type.Assembly, ref assembly, ref name, ref t);
        var sr = new HumanReadableScriptReference(name, assembly);
        if (!scriptRefs.Contains(sr))
        {
            scriptRefs.Add(sr);
        }
    }

    protected void removeScriptReference(Type type, string name)
    {
        //full name of the current assembly            
        string assembly = type.Assembly.FullName;
        Type t = null;
        BoostHelper.AdjustResourceParts(this, type.Assembly, ref assembly, ref name, ref t);
        var sr = new HumanReadableScriptReference(name, assembly);
        if (scriptRefs.Contains(sr))
        {
            scriptRefs.Remove(sr);
        }
    }

    private string _jqBreadCrumb;

    /// <summary>
    /// Unique jQuery pattern that identifies this control
    /// </summary>
    protected string JQBreadCrumb
    {
        get
        {
            if (_jqBreadCrumb == null)
            {
                //StringBuilder sb = new StringBuilder();
                //Control c = this;
                Control c = this.NamingContainer;
                //int step = 1;
                while (c != null && c.ClientID != "__Page")
                {
                    if (c is JQControl) // || step > 1)
                    {
                        _jqBreadCrumb = c.ClientID;
                        break;
                        //sb.Insert(0, " ");
                        //sb.Insert(0, "#" + c.ClientID);
                    }
                    c = c.NamingContainer;
                    //step++;
                }
                //_jqBreadCrumb = sb.ToString();
            }
            return _jqBreadCrumb;
        }
    }

    //regular expression to look for tokens
    private static readonly Regex tokenRegex = new Regex(
        @"##(?<tokenName>[\w\:]+)"
        );



    //actually replaces tokens
    private string tokenReplacer(Match m, bool useContext)
    {
        //token found
        string tokenName = m.Groups["tokenName"].Value;
        string ctlName = null;
        //check if we have a resource token
        if (ResourceHelper.CheckStringForToken(tokenName))
        {
            return "\"" + ResourceHelper.GetStringByToken(tokenName, ResourceType.Portal) + "\"";
        }
        switch (tokenName)
        {
            case "this":
                //special case: seek for the current control
                if (useContext) return "$(__$)";
                ctlName = "#" + this.ClientID; // JQBreadCrumb;
                break;
            case "parent":
                //special case: seek for the direct parent control
                ctlName = "#" + JQBreadCrumb;
                // this.NamingContainer.ClientID;   //NOTE: use parent breadcrumb here
                break;
            default:
                //seek for the child control with the given name
                if (!useContext)
                {
                    Control ctl = getChildByName(tokenName);
                    if (ctl != null) ctlName = "#" + ctl.ClientID;
                }
                //else ctlName = "[id^='" + this.ClientID + "_']" + "[id$='_" + tokenName + "']:first";
                break;
        }
        if(ctlName != null) return "$(\"" + ctlName + "\")";
        if (!useContext) return "$(this)._cc('" + tokenName + "', '" + this.ClientID + "')";
        return "$(__$)._cc('" + tokenName + "')";
    }

    private string tokenReplacerWithContext(Match m)
    {
        return tokenReplacer(m, true);
    }

    private string tokenReplacerWithoutContext(Match m)
    {
        return tokenReplacer(m, false);
    }

    protected virtual Control getChildByName(string name)
    {
        return this.Controls.Cast<Control>().SingleOrDefault(c => c.ID == name);
    }

    //regular expression to insert context holder
    private static readonly Regex contextRegex = new Regex(
        @"^(\s*function\(\s*\)\s*{)", RegexOptions.Multiline
        );

    private static int replacedNum;
    private static string contextReplacer(Match m)
    {
        replacedNum++;
        return "function() { var __$ = this; \r\n";
    }

    /// <summary>
    /// Substitue occurences of tokens of type ##[token] into corresponding jQuery calls
    /// </summary>
    /// <param name="callbackMethod">Callback method definition that contains tokens</param>
    /// <param name="useContext">True if local context is to be used on the client</param>
    protected void PrepareCallbackMethod(JQRaw callbackMethod, bool useContext)
    {
        if(useContext)
        {
            replacedNum = 0;
            callbackMethod.JQRawContent = contextRegex.Replace(callbackMethod.JQRawContent, contextReplacer);
            if(replacedNum == 0) useContext = false;
        }
        if (callbackMethod != null)
        {
            MatchEvaluator me;
            if(useContext) me = tokenReplacerWithContext;
            else me = tokenReplacerWithoutContext;

            //find tokens in callback body and replace them
            callbackMethod.JQRawContent = tokenRegex.Replace(callbackMethod.JQRawContent, me);
        }
    }

    protected void PrepareCallbackMethod(JQRaw callbackMethod)
    {
        PrepareCallbackMethod(callbackMethod, false);
    }

    protected virtual void PrepareCallbackMethods(object @params)
    {
        foreach (PropertyInfo pi in @params.GetType().GetProperties().Where(
                p => p.PropertyType.Equals(typeof(JQRaw))
            ))
        {
            if (pi.GetCustomAttributes(typeof(CallbackMethodAttribute), false).Length > 0)
            {
                //property has the attribute: prepare
                JQRaw pty = (JQRaw)pi.GetValue(@params, null);
                if (pty != null && pty.JQRawContent != null)
                {
                    PrepareCallbackMethod(pty);
                }
            }
        }
    }

    /// <summary>
    /// Returns the script files for the control
    /// </summary>
    /// <returns>Collection that contains ECMAScript (JavaScript) files that have been registered as embedded resources</returns>
    protected override IEnumerable<ScriptReference> GetScriptReferences()
    {
        return scriptRefs;
    }

    private const string selfAlias = "__$";
    protected virtual string GetDescriptorSelector()
    {
        //return this.ClientID;
        return selfAlias;
    }

    protected virtual IEnumerable<ScriptDescriptor> _getScriptDescriptors()
    {
        yield break;
    }

    //private const string afterInitTemplate = "function() {{ var _method = {0}; _method(); $('#{1}').trigger('_loadComplete'); }}";

    protected sealed override IEnumerable<ScriptDescriptor> GetScriptDescriptors()
    {
        var result = new List<ScriptDescriptor>();

        //yield return new JQSelfDescriptor(this.ClientID, selfAlias);
        result.Add(new JQSelfDescriptor(this.ClientID, selfAlias));


        if (PreInit != null)
        {
            //to be executed before initialization
            PrepareCallbackMethod(PreInit, true);
            //yield return new JQDescriptor(GetDescriptorSelector(), "each", true, PreInit);
            result.Add(new JQDescriptor(GetDescriptorSelector(), "each", true, PreInit));
        }

        if(InitData != null)
        {
            foreach (string key in InitData.Keys)
            {
                //initialize with the given object as data
                object data;
                bool useStd = false;
                if (InitData[key] is NativeContainer)
                {
                    data = ((NativeContainer)InitData[key]).Content;
                    useStd = true;
                }
                else data = InitData[key];
                JQDescriptor jdesc = new JQDescriptor(GetDescriptorSelector(), "data", true, key, data);
                if(useStd) jdesc.UseStandardSerializer = true;
                    //yield return jdesc;
                    result.Add(jdesc);
            }
        }

        if (AuthorizationTemplates != null)
        {
            //register authorization templates
            //yield return new JQDescriptor(GetDescriptorSelector(), "pm_registerAuthTemplates", true, AuthorizationTemplates);
            result.Add(new JQDescriptor(GetDescriptorSelector(), "pm_registerAuthTemplates", true, AuthorizationTemplates));
        }

        //enumerate overriden method results
        foreach(ScriptDescriptor sd in _getScriptDescriptors())
        {
           // yield return sd;
            result.Add(sd);
        }

        if (AfterInit != null)
        {
            //to be executed after initialization
            PrepareCallbackMethod(AfterInit, true);
            //AfterInit.JQRawContent = String.Format(afterInitTemplate, AfterInit.JQRawContent, GetDescriptorSelector());
            //yield return new JQDescriptor(GetDescriptorSelector(), "each", true, AfterInit);
            result.Add(new JQDescriptor(GetDescriptorSelector(), "each", true, AfterInit));
        }

        if (ThemePath != null && ThemeCssName != null)
        {
            //load css file dynamically
            string cssURL = VirtualURLHelper.Combine(ThemePath, ThemeCssName);
            DynamicStylesheetDescriptor dsdesc = new DynamicStylesheetDescriptor(cssURL);
            //yield return dsdesc;
            result.Add(dsdesc);
        }

        if (cssRefs.Count > 0)
        {
            DynamicStylesheetDescriptor dsdesc = new DynamicStylesheetDescriptor(cssRefs);
            //yield return dsdesc;
            result.Add(dsdesc);
        }

        //final trigger
        //yield return new JQDescriptor(GetDescriptorSelector(), "trigger", "_loadComplete");

        //yield break;
        return result;
    }

    /// <summary>
    /// Helper method to create URL to an embedded resource
    /// </summary>
    /// <param name="type">The type of the server-side resource</param>
    /// <param name="resourceName">The name of the server-side resource</param>
    /// <returns>The URL reference to the resource</returns>
    protected string GetEmbeddedURL(Type type, string resourceName)
    {
        //get base URL
        string url = Page.ClientScript.GetWebResourceUrl(type, resourceName);
        //attach name of the resource
        return url.Replace("?", "?name=" + resourceName + "&");
    }
}

我将其放在 ascx Control 的页面上: 页面: `<%@ 页面语言=“C#” AutoEventWireup=“true” CodeBehind=“p2.aspx.cs” Inherits=“LWM.Implementation.Portal.Sample.TestOutputCache.p2” %>

<%@ Register TagPrefix="LWM" Src="~/Sample/TestOutputCache/testControl2.ascx" TagName="TestControl2"%>

<LWM:TestControl2 ID="testCached" runat="server" />


</div>
</form>

`

ascx: `<%@ 控制语言="C#" AutoEventWireup="true" CodeBehind="testControl2.ascx.cs" Inherits="LWM.Implementation.Portal.Sample.testControl2" %> <%@ OutputCache Duration="600" VaryByParam="无" %> <%@ Register TagPrefix="Controls" Assembly="LWM.Implementation.Controls" Namespace="LWM.Implementation.Controls.JQComposite" %> 测试2 函数(事件) {

        console.log("afterInit 2");
    }
</AfterInit>

`

我还启用了 ascx 控制缓存。当页面首次加载时一切正常,但是当从服务器缓存获取页面时,所有脚本引用都丢失了......

我搜索了很多,但找不到任何想法。 因此,问题是当从服务器缓存加载控件时,脚本管理器不会生成脚本引用。

I wrote a Simple Control, that implements ScriptControl. This is holder for JQuery framework:

 /// <summary>
/// Generic control with client behavior handled via jQuery
/// </summary>
public abstract partial class JQControl : ScriptControl, INamingContainer
{
    /// <summary>
    /// Client method to be called after jQuery initialization
    /// </summary>
    [PersistenceMode(PersistenceMode.InnerProperty)]
    public JQRaw AfterInit
    {
        get;
        set;
    }

    /// <summary>
    /// Client method to be called before jQuery initialization
    /// </summary>
    [PersistenceMode(PersistenceMode.InnerProperty)]
    public JQRaw PreInit
    {
        get;
        set;
    }

    /// <summary>
    /// Any data to initialize the control with (name-value pairs)
    /// </summary>
    public IDictionary<string, object> InitData
    {
        get; set;
    }

    /// <summary>
    /// Authorization templates to be registered and used by privilege manager
    /// </summary>
    public IDictionary<string, AuthorizationTemplate> AuthorizationTemplates
    {
        get; set;
    }

    /// <summary>
    /// If ThemePath is specified, this css file will be looked for and loaded from the theme folder
    /// </summary>
    protected string ThemeCssName
    {
        get; set;
    }

    private string _themePath;

    /// <summary>
    /// Specifies path to look for custom css and images to enable theming.
    /// </summary>
    public string ThemePath
    {
        get
        {
            return _themePath == null ? DefaultThemeHelper.ThemeName : ResolveClientUrl(_themePath);
        }
        set
        {
            _themePath = value;
        }
    }

    /// <summary>
    /// Collection of streamed javascript files
    /// </summary>
    private readonly List<ScriptReference> scriptRefs = new List<ScriptReference>();

    /// <summary>
    /// Collection of streamed stylesheet files
    /// </summary>
    private readonly List<string> cssRefs = new List<string>();

    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
        FillScriptReferences();
    }

    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);

    }
    protected bool useDynamicCss = true;




    private bool dynamicCssEnabled;
    protected void EnableDynamicCss()
    {
        if(!dynamicCssEnabled)
        {
            //enable dynamic css loading
            addScriptReference(typeof(JQControl), "LWM.Implementation.Controls.DynamicStylesheet.css.js");
            dynamicCssEnabled = true;
        }
    }

    protected virtual void FillScriptReferences()
    {
        Type t = typeof(JQControl);
        addScriptReference(t, "LWM.Implementation.Controls.JScripts.Jquery.js");
        addScriptReference(t, "LWM.Implementation.Controls.JScripts.ExtendJQuery.js");
        addScriptReference(t, "LWM.Implementation.Controls.JScripts.ExtendAJAXDotNet.js");
        addScriptReference(t, "LWM.Implementation.Controls.JQ.ChainRequests.js");
        addScriptReference(t, "LWM.Implementation.Controls.JScripts.jquery.jcache.js");
        addScriptReference(t, "LWM.Implementation.Controls.JScripts.jquery.cookie.js");
        addScriptReference(t, "LWM.Implementation.Controls.JScripts.jquery.offset.js");
        //if ((_themePath != null && ThemeCssName != null))
        {
            EnableDynamicCss();                
        }
    }

    //added to render automatically assigned id, otherwise escaped
    protected override void AddAttributesToRender(HtmlTextWriter writer)
    {
        const string extCss = "jqcontrol";
        this.CssClass = this.CssClass != null ? this.CssClass + " " + extCss : extCss;

        base.AddAttributesToRender(writer);
        writer.AddAttribute(HtmlTextWriterAttribute.Id, ClientID);
        //writer.AddAttribute(HtmlTextWriterAttribute.Class, CssClass);
    }

    /// <summary>
    /// Ataches an embedded script refernnce using its full name
    /// </summary>
    /// <param name="name">Name of the reference</param>
    /// <param name="useBaseClassAssembly">True if using base class assembly</param>
    protected void AttachScriptRefernceByName(string name, bool useBaseClassAssembly)
    {
        //current type
        Type type = this.GetType();
        if (useBaseClassAssembly)
        {
            //base type
            type = type.BaseType;
        }
        addScriptReference(type, name);
    }

    private void _addCssReference(Type type, string name)
    {
        string assembly = type.Assembly.FullName;
        Type t = null;
        if (BoostHelper.AdjustResourceParts(this, type.Assembly, ref assembly, ref name, ref t))
        {
           //  LoggerHelper.LogInfo(String.Format("CSS init with- Client Script:{0}, Type:{1}, Name:{2} ", this.Page.ClientScript.ToString(),t.ToString(),name),"LWMSiteResourceBooster");

            var sr = new DynamicStylesheetScriptReference(this.Page.ClientScript, t, new[] { name });    //(name, assembly);

            if (!scriptRefs.Contains(sr))
            {
                scriptRefs.Add(sr);
            }
        }
        else
        {
            string url = name;  // GetEmbeddedURL(type, name);
            if (!cssRefs.Contains(url))
            {
                cssRefs.Add(url);
            }
        }
    }

    //protected void addCssReference(string name, Type type)
    //{
    //    _addCssReference(type, name);
    //    if (cssRefs.Count > 0)
    //    {
    //        scriptRefs.Add(new DynamicStylesheetScriptReference(this.Page.ClientScript, type, cssRefs.ToArray()));
    //        cssRefs.Clear();
    //    }
    //}

    protected void addCssReference(Type type, params string[] names)
    {
        if (names == null) return;
        foreach (string name in names)
        {
            _addCssReference(type, name);
        }
        if(cssRefs.Count > 0)
        {
            scriptRefs.Add(new DynamicStylesheetScriptReference(this.Page.ClientScript, type, cssRefs.ToArray()));
            cssRefs.Clear();
        }
    }


    protected void removeCssReference(Type type, string name)
    {
        //TODO
        //if (cssRefs.Contains(url))
        //{
        //    cssRefs.Remove(url);
        //}
    }

    protected void addScriptReference(Type type, string name)
    {


        //full name of the current assembly            
        string assembly = type.Assembly.FullName;
        Type t = null;
        BoostHelper.AdjustResourceParts(this, type.Assembly, ref assembly, ref name, ref t);
        var sr = new HumanReadableScriptReference(name, assembly);
        if (!scriptRefs.Contains(sr))
        {
            scriptRefs.Add(sr);
        }
    }

    protected void removeScriptReference(Type type, string name)
    {
        //full name of the current assembly            
        string assembly = type.Assembly.FullName;
        Type t = null;
        BoostHelper.AdjustResourceParts(this, type.Assembly, ref assembly, ref name, ref t);
        var sr = new HumanReadableScriptReference(name, assembly);
        if (scriptRefs.Contains(sr))
        {
            scriptRefs.Remove(sr);
        }
    }

    private string _jqBreadCrumb;

    /// <summary>
    /// Unique jQuery pattern that identifies this control
    /// </summary>
    protected string JQBreadCrumb
    {
        get
        {
            if (_jqBreadCrumb == null)
            {
                //StringBuilder sb = new StringBuilder();
                //Control c = this;
                Control c = this.NamingContainer;
                //int step = 1;
                while (c != null && c.ClientID != "__Page")
                {
                    if (c is JQControl) // || step > 1)
                    {
                        _jqBreadCrumb = c.ClientID;
                        break;
                        //sb.Insert(0, " ");
                        //sb.Insert(0, "#" + c.ClientID);
                    }
                    c = c.NamingContainer;
                    //step++;
                }
                //_jqBreadCrumb = sb.ToString();
            }
            return _jqBreadCrumb;
        }
    }

    //regular expression to look for tokens
    private static readonly Regex tokenRegex = new Regex(
        @"##(?<tokenName>[\w\:]+)"
        );



    //actually replaces tokens
    private string tokenReplacer(Match m, bool useContext)
    {
        //token found
        string tokenName = m.Groups["tokenName"].Value;
        string ctlName = null;
        //check if we have a resource token
        if (ResourceHelper.CheckStringForToken(tokenName))
        {
            return "\"" + ResourceHelper.GetStringByToken(tokenName, ResourceType.Portal) + "\"";
        }
        switch (tokenName)
        {
            case "this":
                //special case: seek for the current control
                if (useContext) return "$(__$)";
                ctlName = "#" + this.ClientID; // JQBreadCrumb;
                break;
            case "parent":
                //special case: seek for the direct parent control
                ctlName = "#" + JQBreadCrumb;
                // this.NamingContainer.ClientID;   //NOTE: use parent breadcrumb here
                break;
            default:
                //seek for the child control with the given name
                if (!useContext)
                {
                    Control ctl = getChildByName(tokenName);
                    if (ctl != null) ctlName = "#" + ctl.ClientID;
                }
                //else ctlName = "[id^='" + this.ClientID + "_']" + "[id$='_" + tokenName + "']:first";
                break;
        }
        if(ctlName != null) return "$(\"" + ctlName + "\")";
        if (!useContext) return "$(this)._cc('" + tokenName + "', '" + this.ClientID + "')";
        return "$(__$)._cc('" + tokenName + "')";
    }

    private string tokenReplacerWithContext(Match m)
    {
        return tokenReplacer(m, true);
    }

    private string tokenReplacerWithoutContext(Match m)
    {
        return tokenReplacer(m, false);
    }

    protected virtual Control getChildByName(string name)
    {
        return this.Controls.Cast<Control>().SingleOrDefault(c => c.ID == name);
    }

    //regular expression to insert context holder
    private static readonly Regex contextRegex = new Regex(
        @"^(\s*function\(\s*\)\s*{)", RegexOptions.Multiline
        );

    private static int replacedNum;
    private static string contextReplacer(Match m)
    {
        replacedNum++;
        return "function() { var __$ = this; \r\n";
    }

    /// <summary>
    /// Substitue occurences of tokens of type ##[token] into corresponding jQuery calls
    /// </summary>
    /// <param name="callbackMethod">Callback method definition that contains tokens</param>
    /// <param name="useContext">True if local context is to be used on the client</param>
    protected void PrepareCallbackMethod(JQRaw callbackMethod, bool useContext)
    {
        if(useContext)
        {
            replacedNum = 0;
            callbackMethod.JQRawContent = contextRegex.Replace(callbackMethod.JQRawContent, contextReplacer);
            if(replacedNum == 0) useContext = false;
        }
        if (callbackMethod != null)
        {
            MatchEvaluator me;
            if(useContext) me = tokenReplacerWithContext;
            else me = tokenReplacerWithoutContext;

            //find tokens in callback body and replace them
            callbackMethod.JQRawContent = tokenRegex.Replace(callbackMethod.JQRawContent, me);
        }
    }

    protected void PrepareCallbackMethod(JQRaw callbackMethod)
    {
        PrepareCallbackMethod(callbackMethod, false);
    }

    protected virtual void PrepareCallbackMethods(object @params)
    {
        foreach (PropertyInfo pi in @params.GetType().GetProperties().Where(
                p => p.PropertyType.Equals(typeof(JQRaw))
            ))
        {
            if (pi.GetCustomAttributes(typeof(CallbackMethodAttribute), false).Length > 0)
            {
                //property has the attribute: prepare
                JQRaw pty = (JQRaw)pi.GetValue(@params, null);
                if (pty != null && pty.JQRawContent != null)
                {
                    PrepareCallbackMethod(pty);
                }
            }
        }
    }

    /// <summary>
    /// Returns the script files for the control
    /// </summary>
    /// <returns>Collection that contains ECMAScript (JavaScript) files that have been registered as embedded resources</returns>
    protected override IEnumerable<ScriptReference> GetScriptReferences()
    {
        return scriptRefs;
    }

    private const string selfAlias = "__$";
    protected virtual string GetDescriptorSelector()
    {
        //return this.ClientID;
        return selfAlias;
    }

    protected virtual IEnumerable<ScriptDescriptor> _getScriptDescriptors()
    {
        yield break;
    }

    //private const string afterInitTemplate = "function() {{ var _method = {0}; _method(); $('#{1}').trigger('_loadComplete'); }}";

    protected sealed override IEnumerable<ScriptDescriptor> GetScriptDescriptors()
    {
        var result = new List<ScriptDescriptor>();

        //yield return new JQSelfDescriptor(this.ClientID, selfAlias);
        result.Add(new JQSelfDescriptor(this.ClientID, selfAlias));


        if (PreInit != null)
        {
            //to be executed before initialization
            PrepareCallbackMethod(PreInit, true);
            //yield return new JQDescriptor(GetDescriptorSelector(), "each", true, PreInit);
            result.Add(new JQDescriptor(GetDescriptorSelector(), "each", true, PreInit));
        }

        if(InitData != null)
        {
            foreach (string key in InitData.Keys)
            {
                //initialize with the given object as data
                object data;
                bool useStd = false;
                if (InitData[key] is NativeContainer)
                {
                    data = ((NativeContainer)InitData[key]).Content;
                    useStd = true;
                }
                else data = InitData[key];
                JQDescriptor jdesc = new JQDescriptor(GetDescriptorSelector(), "data", true, key, data);
                if(useStd) jdesc.UseStandardSerializer = true;
                    //yield return jdesc;
                    result.Add(jdesc);
            }
        }

        if (AuthorizationTemplates != null)
        {
            //register authorization templates
            //yield return new JQDescriptor(GetDescriptorSelector(), "pm_registerAuthTemplates", true, AuthorizationTemplates);
            result.Add(new JQDescriptor(GetDescriptorSelector(), "pm_registerAuthTemplates", true, AuthorizationTemplates));
        }

        //enumerate overriden method results
        foreach(ScriptDescriptor sd in _getScriptDescriptors())
        {
           // yield return sd;
            result.Add(sd);
        }

        if (AfterInit != null)
        {
            //to be executed after initialization
            PrepareCallbackMethod(AfterInit, true);
            //AfterInit.JQRawContent = String.Format(afterInitTemplate, AfterInit.JQRawContent, GetDescriptorSelector());
            //yield return new JQDescriptor(GetDescriptorSelector(), "each", true, AfterInit);
            result.Add(new JQDescriptor(GetDescriptorSelector(), "each", true, AfterInit));
        }

        if (ThemePath != null && ThemeCssName != null)
        {
            //load css file dynamically
            string cssURL = VirtualURLHelper.Combine(ThemePath, ThemeCssName);
            DynamicStylesheetDescriptor dsdesc = new DynamicStylesheetDescriptor(cssURL);
            //yield return dsdesc;
            result.Add(dsdesc);
        }

        if (cssRefs.Count > 0)
        {
            DynamicStylesheetDescriptor dsdesc = new DynamicStylesheetDescriptor(cssRefs);
            //yield return dsdesc;
            result.Add(dsdesc);
        }

        //final trigger
        //yield return new JQDescriptor(GetDescriptorSelector(), "trigger", "_loadComplete");

        //yield break;
        return result;
    }

    /// <summary>
    /// Helper method to create URL to an embedded resource
    /// </summary>
    /// <param name="type">The type of the server-side resource</param>
    /// <param name="resourceName">The name of the server-side resource</param>
    /// <returns>The URL reference to the resource</returns>
    protected string GetEmbeddedURL(Type type, string resourceName)
    {
        //get base URL
        string url = Page.ClientScript.GetWebResourceUrl(type, resourceName);
        //attach name of the resource
        return url.Replace("?", "?name=" + resourceName + "&");
    }
}

I place it on page into ascx Control:
Page: `<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="p2.aspx.cs" Inherits="LWM.Implementation.Portal.Sample.TestOutputCache.p2" %>

<%@ Register TagPrefix="LWM" Src="~/Sample/TestOutputCache/testControl2.ascx" TagName="TestControl2"%>

<LWM:TestControl2 ID="testCached" runat="server" />


</div>
</form>

`

ascx: `<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="testControl2.ascx.cs"
Inherits="LWM.Implementation.Portal.Sample.testControl2" %>
<%@ OutputCache Duration="600" VaryByParam="None" %>
<%@ Register TagPrefix="Controls" Assembly="LWM.Implementation.Controls" Namespace="LWM.Implementation.Controls.JQComposite" %>

Test 2

function (evt)
{

        console.log("afterInit 2");
    }
</AfterInit>

`

Also i enable ascx control cache. When page first loaded all ok, but when page getted from server cache all script references are missing...

I search a lot and can't find any idea.
So, problem is that scriptmanager do not generate script reference when control loaded from server cache.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

烏雲後面有陽光 2024-10-03 15:45:48

这是 OutputCaching 和脚本管理器的错误,官方是 被 Microsoft 认可

有一种解决方法可以手动将脚本添加到 scriptmanager:

 <asp:ScriptManager ID="ScriptManager1" runat="server">
        <Scripts>
            <asp:ScriptReference Name="AjaxControlToolkit.Common.Common.js" Assembly="AjaxControlToolkit" />
            <asp:ScriptReference Name="AjaxControlToolkit.ExtenderBase.BaseScripts.js" Assembly="AjaxControlToolkit" />
            <asp:ScriptReference Name="AjaxControlToolkit.TextboxWatermark.TextboxWatermark.js"
                Assembly="AjaxControlToolkit" />
        </Scripts>
    </asp:ScriptManager>

This is bug with OutputCaching and Script Manager, which officially was recognized by Microsoft

There is workaround to add scripts to scriptmanager manually:

 <asp:ScriptManager ID="ScriptManager1" runat="server">
        <Scripts>
            <asp:ScriptReference Name="AjaxControlToolkit.Common.Common.js" Assembly="AjaxControlToolkit" />
            <asp:ScriptReference Name="AjaxControlToolkit.ExtenderBase.BaseScripts.js" Assembly="AjaxControlToolkit" />
            <asp:ScriptReference Name="AjaxControlToolkit.TextboxWatermark.TextboxWatermark.js"
                Assembly="AjaxControlToolkit" />
        </Scripts>
    </asp:ScriptManager>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文