Search code examples
sharepoint-2010.net-3.5asp.net-ajaxupdatepanelpartial-postback

Script References not loaded in Partial PostBack when specified as "new ScriptReference(resourceName,assemblyName)"


I have created an ASP.NET AJAX control which implement IScriptControl as per Adding Client Capabilities to a Web Server Control. This control works as expect - when the script resource is loaded; however, the problematic issue is the script resource is not always loaded.

The control loads all the appropriate referenced resources when loaded from a Full PostBack. This is not terribly surprising. The control works. It follows the appropriate IScriptControl rules, registers the Script Control and renders the appropriate Script Descriptors. Both GetScriptReferences and GetScriptDescriptions are implemented.

Now, when GetScriptReferences is written as ..

public IEnumerable<ScriptReference> GetScriptReferences()
{
  return new List<ScriptReference> {
    new ScriptReference("Resource.js", GetType().Assembly.FullName)
  }
}

.. then the resource is not loaded by the ScriptManager in the Partial PostBack update!

As such, if the control can only be used if it is first loaded in a Full PostBack so the appropriate script references have already been loaded. In cases where it works (e.g. is in a Full PostBack), the resource fetch can be seen as http://dev/ScriptResource.axd?d=...

However, when the resource is loaded via ..

public IEnumerable<ScriptReference> GetScriptReferences()
{
  return new List<ScriptReference> {
    new ScriptReference(Page.ClientScript.GetWebResourceUrl(GetType(), "Resource.js"))
  };
}

.. then the resource is loaded, even in a Partial PostBack. The request can be seen in the browsers network log as http://dev/WebResource.axd?d=... I would like to avoid this second form as then I have to manually tack on the Sys.Application.notifyScriptLoaded code manually.

An ASP.NET 3.5 ScriptManager is being created in a custom SharePoint 2010 Master Page (such that it replaces the default ScriptManager control) with the following configuration:

<aspExt:ScriptManager runat="server" ID="MyScriptManager"
    EnablePartialRendering="True" EnablePageMethods="True" EnableViewState="True"
    EnableHistory="True" EnableSecureHistoryState="False"
    EnableScriptLocalization="False" EnableScriptGlobalization="False"
    LoadScriptsBeforeUI="True">
</aspExt:ScriptManager>

Manually force-load the scripts via ScriptManager.RegisterClientScriptResource (which loads from http://dev/ScriptResource.axd?d=..) "works" but in doing so the control needs to break the IScriptControl model and not return any references from GetScriptReferences so that consistent behavior can be ensured in both Full and Partial PostBack situations. Otherwise, the same resource will be loaded multiple times when the script resource are actually loaded correctly in the Full PostBack situation.


Solution

  • This appears to be an issue with SharePoint 2010 and I was finally able to dig up some information on this post.

    This is a known issue in Sharepoint 2010. The script resources are not loaded if the controls are not visible initially ..

    .. The "Sharepoint 2010 not emitting javascript links on partial postback" problem .. occurs, if controls are added (OR made visible) during a partial postback.

    Thankfully,

    Microsoft has finally addressed this issue as well in one of the Sharepoint 2010 cumulative updates for October 2011. Installing this update should generally fix the problems with hidden ajax controls registering their scripts.

    It appears SharePoint Server 2010 cumulative update package (SharePoint server-package): October 25, 2011 is the first CU with the fix - although I have not verified this.


    For historical reference - or for poor people like me who can't ensure that the CU/SP applied - a "work-about" is to manually register the resources. (This was also found in the linked post.)

    public class MyComboBox : RadComboBox
    {
        protected override System.Collections.Generic.IEnumerable<System.Web.UI.ScriptReference> GetScriptReferences()
        {
    #if MANUAL_SCRIPT_POSTBACK_FIX
            HashSet<string> registeredNames = new HashSet<string>();
            ReadOnlyCollection<RegisteredScript> registeredScripts = ScriptManager.GetCurrent(Page).GetRegisteredClientScriptBlocks();           
            foreach (RegisteredScript registeredScript in registeredScripts)
            {
                registeredNames.Add(registeredScript.Key);
            }
             
            foreach (ScriptReference reference in base.GetScriptReferences())
            {
                if (!registeredNames.Contains(reference.Name))
                {
                    ScriptManager.RegisterClientScriptResource(this, typeof(MyComboBox).BaseType, reference.Name);
                }
            }
            return new List<ScriptReference>();
    #else
            return base.GetScriptReferences();
    #endif     
        }
    }