views:

3858

answers:

4

I've been tryin' to use call Page Methods from my own javascript code but it doesn't work. If I use JQuery AJAX Method I can sucessfully call the Page Methods, but the problem is that I need to do this from my own Javascript code because in the place where I work we can't use Third Party Javascript Lybraries and we are building our own library. Whenever I use JQuery AJAX methods i get the result of the Page Method, and when I use my Custom JS methods I get Whole page back from the AJAX Request. There must be something different in the way JQuery handles AJAX requests. Does anyone know ?

Below is the code I use to call the same Page Method with JQuery wich works and the code that I'm using to call it on my own.

=== jQuery ====

// JScript File
$(document).ready(function() {
  $("#search").click(function() {
    $.ajax({
      type: "POST",
      url: "Account.aspx/GetData",
      data: "{}",
      contentType: "application/json; charset=utf-8",
      dataType: "json",
      success: function(msg) {
        // Substitui o conteúdo da DIV vom o retorno do Page Method.
        displayResult(msg);
      }
    });
  });
});

=== Custom JS ===

function getHTTPObject() {
    var xhr = false;
    if (window.XMLHttpRequest) {
        xhr = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        try {
            xhr = new ActiveXObject("Msxml2.XMLHTTP");
        } catch(e) {
            try { 
                xhr = new ActiveXObject("Microsoft.XMLHTTP");
            } catch(e) {
                xhr = false;
            }
        }
    }
    return xhr;
}

function prepareLinks() {
    var btn  = document.getElementById("search");
    btn.onclick = function() {
        var url = "Account.aspx/GetData"
        return !grabFile(url);
    }    
}

function grabFile(file) {
    var request = getHTTPObject();
    if (request) {
        displayLoading(document.getElementById("result"));
        request.onreadystatechange = function() {
            parseResponse(request);
        };
        //Abre o SOCKET
        request.open("GET", file, true);
        //Envia a requisição
        request.send(null);
        return true;
    } else {
        return false;
    }
}

function parseResponse(request) {
    if (request.readyState == 4) {
        if (request.status == 200 || request.status == 304) {
            var details = document.getElementById("result");
            details.innerHTML = request.responseText;
            fadeUp(details,255,255,153);
        }
    }
}

function addLoadEvent(func) {
    var oldonload = window.onload;
    if (typeof window.onload != 'function') {
        window.onload = func;
    } else {
        window.onload = function() {
        if (oldonload) {
            oldonload();
        }
            func();
        }
    }
}

addLoadEvent(prepareLinks);

UPDATE: I've decided to accept Stevemegson's since his answer was the actual cause to my problem. But I'd like to share with yo a few alterantives I've found to this problem.

Stevemegson's Answer: All I had to do was to change to a POST request and set the request header to JSON,that solved my problem on requesting Page Methods, but now I'm haing a hard time on handling the Response (I'll say more about that on another question).

Here's the right code to get this stuff:

print("function prepareLinks() {
var list = document.getElementById("search");
list.onclick = function() {
    var url = "PMS.aspx/GetData"
        return !grabFile(url);
    } }");

print("function grabFile(file) {
var request = getHTTPObject();
if (request) {
    //Evento levantado pelo Servidor a cada mudança de Estado na 
    //requisição assíncrona
    request.onreadystatechange = function() {
        parseResponse(request);
    };        
    //USE POST
    request.open('POST', file, true);
    //SET REQUEST TO JSON
    request.setRequestHeader('Content-Type', 'application/json');
    // SEND REQUISITION
    request.send(null)
    return true;
} else {
    return false;
}
}");

Brendan's Answer: Through Brendan's answer I did a little research on the ICallBack Interface and the ICallBackEventHandler. To my surprise that's a way to develop aspx pages using Microsoft's implementation of AJAX Request's. This turns out to be a really interesting solution, since it dosen't require any JS Library to work out and it's inside .Net Framework and I believe that only a few people know about this stuff (at least those that are around me didn't know about it at all). If you wanna know more abou ICallBack check this link text on MS or just copy and paste Brendan's answer.

A Third Solution: Another solution I found was to instead of creating ASPX pages to handle my server side code I would implement HTML pages and call ASHX files that would do the same thing but they would use less bandwith than an ASPX page. One great about this solution is that I maged to make it work with POST and GET requisitions. Below is the code.

ASHX Code:

print("Imports System.Web
       Imports System.Web.Services
       Public Class CustomHandler
         Implements System.Web.IHttpHandler
          Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "text/plain"
Dim strBuilder As New System.Text.StringBuilder
strBuilder.Append("<p>")
strBuilder.Append("Your name is: ")
strBuilder.Append("<em>")
strBuilder.Append(context.Request.Form(0))
strBuilder.Append("</em>")
strBuilder.Append("</p>")
context.Response.Write(strBuilder.ToString)
End Sub
ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
  Return False
End Get End Property End Class");

JavaScript File:

print("function prepareLinks() {
var list = document.getElementById("search");
list.onclick = function() {
    var url = "CustomHandler.ashx"
        return !grabFile(url);
    }    
}");

print("function grabFile(file) {
var request = getHTTPObject();
if (request) {
    request.onreadystatechange = function() {
        parseResponse(request);
    };
    //VERSÃO do POST
    request.open('POST', file, true);
    request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    request.send('name=Helton Valentini')
    return true;
} else {
    return false;
} }");

With any of these three options we can make asynchronous calls without use JQuery, using our own Javacript or using the resources Microsoft embeeded on .Net Framework.

I hope this helps our some of you.

+2  A: 

One relatively easy solution is to have your code-behind implement ICallbackEventHandler. Its a little crude compared to JQuery but it works.

Partial Public Class state
    Implements ICallbackEventHandler

    Private _callbackArg As String

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        RegisterCallbackScript()
    End Sub

    Private Sub RegisterCallbackScript()  
        Dim cbRef As String = Page.ClientScript.GetCallbackEventReference(Me, "args", "RecieveServerData", "context")
        Dim cbScript As String = "function CallServer(args, context) {" & cbRef & "; }"
        ClientScript.RegisterClientScriptBlock(Me.GetType(), "CallServer", cbScript, True)
    End Sub

    Public Sub RaiseCallbackEvent(ByVal eventArgs As String) Implements ICallbackEventHandler.RaiseCallbackEvent
        _callbackArg = eventArgs
    End Sub

    Private Function GetCallbackResults() As String Implements ICallbackEventHandler.GetCallbackResult
        Dim args As String() = _callbackArg.Split(CChar("~"))
        If args(0) = "search"
            Return args(0) + "~" + GetSearchResults(args(1))
        End If
    End Function

    Private Function GetSearchResults(ByVal keyword As String) As String
        Dim htmlResults As String
        //Build your html here
        Return htmlResults 
    End Fuction

End Class

//Javascript

function searchButtonClicked(keyword) {
    CallServer('search~' + keyword);
}

function RecieveServerData(arg, context) {
    var args = arg.split('~');
    switch(args[0]){
        case 'search':
            document.getElementById('result').innerHTML = args[1]
            break;
    }
}

Hope this helps.

Brendan Kendrick
+1  A: 

You're requesting the URL with a GET, while the jQuery code uses a POST. I expect that a Page Method can only be called through a POST, to allow you to include any parameters in the body of your request. You may also need to set the Content-Type of your request to application/json, as the jQuery code does - I don't know whether or not .NET will accept other content types.

stevemegson
+1  A: 

If you are using ASP.NET AJAX you don't need to do any of this. There is a well defined way of using PageMethods that is a whole lot less complex.

Codebehind

    [WebMethod]
    public static Whatever GetWhatever( int someParameter, string somethingElse )
    {
       ... make a Whatever ...

       return whatever;
    }

Page

...
<script type="text/javascript">
   function invokePageMethod(button)
   {
       var ctx = { control: button };
       var someParameter = ...get value from a control...
       var somethingElse = ...get another value from a control...
       PageMethods.GetWhatever( someParameter, somethingElse, success, failure, ctx );
   }

   function success(result,context) {
       ... rearrange some stuff on the page...
   }

   function failure(error,context) {
       ... show some error message ...
   }
</script>
...

<asp:ScriptManager runat="server" id="myScriptManager" EnablePageMethods="true">
</asp:ScriptManager>

...

<input type="button" onclick="invokePageMethod(this);" value="Do Something" />
tvanfosson
In order to do that I'd have to put a Script Manager on my page and set enable page methods to True, so that a proxy would be created. Using the examples I've described above I don't need to do any of these.
Yeah, but you also have to write and maintain your own code to do AJAX postbacks. I'd prefer to rely on the framework and spend my time writing code that more directly benefits my app.
tvanfosson
A: 

AjaxPRO.NET...?

Thomas Hansen