Inconsistent LinkButton PageMethod behavior in dif

2019-04-02 17:49发布

问题:

I have a LinkButton on a page that performs a post-back, but also has an onClientClick event. The idea is to set some session variables in the background from client-side data (don't ask).

I've placed a break point in the web method to step through our code, and what we're experiencing is that depending on the browser, the PageMethods may return a success message, failure message, or no message at all. Additionally, the web method may or may not get called, regardless of the PageMethods result.

Here's a handy little chart of our results:

Browser          PageMethods    WebMethod
--------------   -------------  --------------------
IE 8, 9, 10      Success        Called successfully
Safari 5.1.7     Failure        *Never called*
Firefox 25.0.1   *Neither*      Called successfully
Chrome v31       Failure        Called successfully

That's four different browsers, and four different results.

I've tried generating the link button in both server-side and client-side code with the same effect, and without even setting the session variables in the WebMethod, with the same results.

The code can be reproduced with the following simple code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script type="text/javascript">

    function doStuff() {
        var a = 'a';
        var b = 'b';

        PageMethods.doStuffWebMethod(a, b, doStuffSuccess, doStuffFail);
    }

    function doStuffSuccess() {
        alert(Success!');
    }
    function doStuffFail() {
        alert(Failure!');
    }

</script>

<html>
    <body style="background-color:#f3f4f6;" >

        <form runat="server" name="mainForm" id="mainForm" action="Test.aspx">

            <asp:ScriptManager ID="ScriptManager1"  EnablePageMethods="true" runat="server"></asp:ScriptManager>

            <asp:LinkButton runat="server" CausesValidation="false" OnClientClick="doStuff();">Do stuff!</asp:LinkButton>

        </form>
    </body>
</html>

and

protected void Page_Load(object sender, EventArgs e)
{
    LinkButton lbAdd = new LinkButton();
    lbAdd.Text = "Web method test";
    lbAdd.CausesValidation = false;
    lbAdd.OnClientClick = "doStuff();";
    mainForm.Controls.Add(lbAdd);
}

[WebMethod]
public static void doStuffWebMethod(string a, string b)
{
    try
    {
        //System.Web.HttpContext.Current.Session["a"] = a;
        //System.Web.HttpContext.Current.Session["b"] = b;
        string x = a + b;
    }
    catch (Exception ex)
    {
        //
    }
}

The question:

Why is my web method failing in Safari, and giving me one of three different return messages in three other browsers?

How can I change this code to get it to work in the browsers mentioned?

回答1:

The reason the call to your web method is failing is because your are not canceling the postback of your LinkButton. You have to return false from the OnClientClick event to cancel the postback. The code below should fix it:

function doStuff() {
  var a = 'a';
  var b = 'b';

  PageMethods.doStuffWebMethod(a, b, doStuffSuccess, doStuffFail);
  return false; // Cancel postback.
}

function doStuffSuccess() {
  alert('Success!');
}

function doStuffFail() {
  alert('Failure!');
}

<asp:LinkButton ID="mybutton"  runat="server" CausesValidation="false" OnClientClick="return doStuff();">Do stuff!</asp:LinkButton>

For a more sophisticated solution for canceling the default behaviour of a browser (postback) please have a look on the following stackoverflow question and answer.

The reason you are getting those different results for the different browsers is maybe due to different implementations of the browser vendors. But I am not sure about this.

You can also verify this behaviour by creating a network protocol trace (press F12 in Google Chrome browser and switch to the network tab).

The protocol in case you do not return false from the doStuff() method:

  1. The page method doStuffWebMethod is called. Then you get the JavaScript message box. (HTTP POST)
  2. Your WebForm.aspx is requested. (HTTP POST)
  3. Then WebResource.axd and ScriptResource.axd is requested. (HTTP GET)

Number 2. and 3. shows that a postback is executed after the request of your page method.

The protocol in case you do return false from the doStuff() method:

  1. Only the page method doStuffWebMethod is called. (HTTP POST)

The second trace clearly shows that there is no postback executed.

If you want the postback to happen for your LinkButton then you could manually trigger the postback in the JavaScript success handler using the __doPostBack() method after the page method comes back:

function doStuffSuccess() {
  alert('Success!');

  __doPostBack('<%= mybutton.UniqueID %>', '');  // trigger the postback.
}