Freigeben über


Enabling ScriptManager PageMethods doesn’t work in some scenarios in SharePoint 2013

I worked on a case where the problem was that PageMethods won’t execute from within a SharePoint 2013 application page (page deployed to the _layouts folder).  To replicate the problem, I had a custom master page deployed through a VS 2012 solution with the following definition within the <body/> element.

 <asp:ScriptManager id="ScriptManager" runat="server" EnablePageMethods="true" EnablePartialRendering="true" EnableScriptGlobalization="false" EnableScriptLocalization="true" />
  
       <script type="text/javascript">
  
           function CallMe() {
               alert("called from master page");
               // call server side method
               PageMethods.TestMethod(OnRequestComplete, OnRequestError);
           }
  
           
           function OnRequestComplete(res, userContext, methodName) {
  
               alert(res);
  
           }
  
           function OnRequestError(error, userContext, methodName) {
  
               if (error != null) {
  
                   alert(error.get_message());
  
               }
  
           }
  
     </script>

And I had my TestMethod defined in my application page as shown below.

 using System;
 using Microsoft.SharePoint;
 using Microsoft.SharePoint.WebControls;
 using System.Web.Services;
  
 namespace SPProj.Layouts.SPProj
 {
     public partial class ApplicationPage1 : LayoutsPageBase
     {
         protected void Page_Load(object sender, EventArgs e)
         {
             Button1.Attributes.Add("onclick", "javascript:CallMe()");
         }
  
         [WebMethod]
         public static string TestMethod()
         {
             return "Hello";
         }
     }
 }

Notice the ‘onclick’ attribute added to the server-side button control in the Page_Load event.  The idea is, when this page is loaded and the button is clicked, we call the “CallMe()” function defined in the master page.  And this client-side function will call the server-side TestMethod method by virtue of having PageMethods enabled.  But this is what happens in SharePoint 2013.

The page loads.

image

Click the button.

image

Click OK on this alert and the second message box won’t come up.  You might have already noticed the JavaScript error in IE status bar.  Double-click on it and you’ll see this error.

image

Apparently, this is because of anonymous JavaScript functions being pushed to the page by the new web-scoped feature called “Following Content”.  Here’s a snippet from IE Developer Tools.  For brevity, only relevant snippet is shown.

 PageMethods.set_path("applicationpage1.aspx");
 PageMethods.TestMethod= function(onSuccess,onFailed,userContext) {
 /// <param name="succeededCallback" type="Function" optional="true" mayBeNull="true"></param>
 /// <param name="failedCallback" type="Function" optional="true" mayBeNull="true"></param>
 /// <param name="userContext" optional="true" mayBeNull="true"></param>
 PageMethods._staticInstance.TestMethod(onSuccess,onFailed,userContext); }
  
 // from custom action with id = "FollowingCalloutScriptBlock"
 (function(){
  
         if (typeof(_spBodyOnLoadFunctions) === 'undefined' || _spBodyOnLoadFunctions === null) {
             return;
         }
         _spBodyOnLoadFunctions.push(function() {

The problem is that when PageMethods are pushed to the page, a semi-colon isn’t added to properly terminate the JavaScript block.  This is actually not a SharePoint but ASP.NET issue that PageMethods are not properly block terminated.  Since the following JavaScript code is anonymous function at runtime it’s considered to be in the same block and executed, which causes the object expected error.

There are multiple ways to fix it.

1. Deactivate “Following Content” feature.  Not a good one, but if this feature is not being used (which is highly unlikely), then simply deactivating it resolves this error.

2. Modify the “Following Content” feature.  Change the 2 functions defined in the ScriptBlock of <CustomAction/> element to be named functions instead of anonymous.  Deactivate/Uninstall “Following Content” feature.  Install/Activate “Following Content” feature.  THIS OF COURSE, IS UNSUPPORTED.

3. Override the Render method in the application page and inject a semi-colon character.  Below is the modified application page code.

 using System;
 using Microsoft.SharePoint;
 using Microsoft.SharePoint.WebControls;
 using System.Web.Services;
  
 namespace SPProj.Layouts.SPProj
 {
     public partial class ApplicationPage1 : LayoutsPageBase
     {
         protected void Page_Load(object sender, EventArgs e)
         {
             Button1.Attributes.Add("onclick", "javascript:CallMe()");
         }
  
         [WebMethod]
         public static string TestMethod()
         {
             return "Hello";
         }
  
         protected override void Render(System.Web.UI.HtmlTextWriter writer)
         {
             System.Web.UI.ScriptManager.RegisterClientScriptBlock(this, typeof(ApplicationPage1), "semicolon", ";", true);
             base.Render(writer);
         }
     }
 }

Once you deploy this solution, browse to the application page and watch the scripts pushed using IE Developer Tools, you’ll see this.

 PageMethods.set_path("applicationpage1.aspx");
 PageMethods.TestMethod= function(onSuccess,onFailed,userContext) {
 /// <param name="succeededCallback" type="Function" optional="true" mayBeNull="true"></param>
 /// <param name="failedCallback" type="Function" optional="true" mayBeNull="true"></param>
 /// <param name="userContext" optional="true" mayBeNull="true"></param>
 PageMethods._staticInstance.TestMethod(onSuccess,onFailed,userContext); }
 ;
 // from custom action with id = "FollowingCalloutScriptBlock"
 (function(){
  
         if (typeof(_spBodyOnLoadFunctions) === 'undefined' || _spBodyOnLoadFunctions === null) {
             return;
         }
         _spBodyOnLoadFunctions.push(function() {

Notice that “;” character after the PageMethods declaration just before the anonymous functions from “Following Content” feature starts.  Now, when the application page is browsed.

image

And the button is clicked.

image

The first alert is displayed and when you click OK, you’ll see the second alert as well.

image

That resolves this issue.  Hope this post was helpful.

Cross post from https://blogs.msdn.com/sridhara

Comments

  • Anonymous
    January 01, 2003
    Glad this post helped you Poolio!  We haven't heard of a plan that this will be fixed in a future CU.

  • Anonymous
    August 19, 2013
    The comment has been removed

  • Anonymous
    March 20, 2014
    This one saved my day!

  • Anonymous
    May 23, 2014
    Perfect Thanks

  • Anonymous
    August 03, 2015
    You can change without custom master page.
    protected void Page_Load(object sender, EventArgs e)
    {
    System.Web.UI.ScriptManager.GetCurrent(Page).EnablePageMethods = true;
    }

    • Anonymous
      March 20, 2019
      Great info! Thanks Hemen for your reply as well!
  • Anonymous
    November 08, 2017
    Wow, thanks )