16

I have method like this in my .cs :

[System.Web.Services.WebMethod]
public static void GetServiceInformation(IInfo x) //IInfo  is an interface
{
    x.l_power = true;
    x.lb_InboxCount = UserTrans.GetInbox(int.Parse(emp_num), 0);
}

Now i want to call this method through a javascript method as a page method but it doesn't work .

<script type ="text/javascript">

    function GetInfo() {
        PageMethods.GetServiceInformation(this);
    }
   window.onload = setTimeout("GetInfo()", 3000);
</script>

  <telerik:RadScriptManager ID="RadScriptManager1" runat="server" EnablePageMethods="true">
  </telerik:RadScriptManager>

My .cs :

 public partial class AppMaster : Log, IInfo //My page
    {
        public string Inbox
        {
            get
            {
                return hpl_Inbox.NavigateUrl;
            }

            set
            {
                hpl_Inbox.NavigateUrl = value;
            }
        }
        public string Draft
        {
            get
            {
                return hpl_Draft.NavigateUrl;
            }

            set
            {
                hpl_Draft.NavigateUrl = value;
            }
        }

        public string New
        {
            get
            {
                return hpl_New.NavigateUrl;
            }
            set
            {
                hpl_New.NavigateUrl = value;
            }
        }
        public string Approved
        {
            get
            {
                return hpl_Approved.NavigateUrl;
            }
            set
            {
                hpl_Approved.NavigateUrl = value;
            }
        }
    //------- etc
 }

My interface :

public interface IInfo
    {
        string Inbox { get; set; }
        string Draft { get; set; }
        string New { get; set; }
        string Approved { get; set; }
        string archive { get; set; }
        string search { get; set; }
        string cand { get; set; }
        string pri { get; set; }
        string power { get; set; }
        string admin { get; set; }
        string help { get; set; }
        bool l_cand { get; set; }
        bool l_pri { get; set; }
        bool l_power { get; set; }
        bool l_admin { get; set; }

        string lb_ApprovedCount { get; set; }
        string lb_InboxCount { get; set; }
        string lb_archive { get; set; }
        string lb_DraftCount { get; set; }

    }
Anyname Donotcare
  • 11,113
  • 66
  • 219
  • 392
  • So you want call server side code through client side? O.o – Khamidulla Dec 29 '13 at 10:28
  • @antindexer : yeah , this's a special need – Anyname Donotcare Dec 29 '13 at 10:30
  • 2
    You are passing `this` to the page method in JavaScript. While you have an interface in your C# code. This can not be achieved this way. Tell us more about what you are trying to do, so we can help. – Delphi.Boy Dec 29 '13 at 10:40
  • @Delphi.Boy : i have some controls and i i set those controls through the interface , my page implement the interface `public partial class AppMaster : Log, IInfo` i want to pass the interface so i can set the properties in it – Anyname Donotcare Dec 29 '13 at 10:44
  • GetServiceInformation(IInfo x) should be GetServiceInformation(object x),then js function will call page method – HenryChuang Jan 06 '14 at 09:27
  • @just_name please give it a look at my answer. thanks – João Pinho Jan 06 '14 at 15:28
  • @JoãoPinho :please take a look at my question again , i revise it so u could understand what i mean , i want to pass `this` the current object of my page `AppMaster` so i could set some controls in that page after the `page load` – Anyname Donotcare Jan 09 '14 at 09:15
  • this question is crazy. Why do you need Page Methods and ajax to set the controls? Can't you just set the control from javascript? What controls are you trying to set? And why? Can you give a bit of a context to your question instead of showing some crazy code that's obviously reinventing the wheel? – Leo Jan 14 '14 at 07:36
  • @Leo:i'm not trying to invent the wheel . what i want to do is setting some controls (labels , hyperlinks ...etc) wiz values comes from server side after `the page load` because those calculations take a lot of time so i don't want the user to wait those analytical values , i want them rendered after the page load event in the background , so i try to use ajax to do what i want , if u have any ideas instead of being nervous , i'll be grateful :) – Anyname Donotcare Jan 14 '14 at 07:46
  • 1
    @just_name sorry, don't get it the wrong way...I'm just trying to squeeze out some information from you because it's still not clear to me why you have gone that way in your implementation. It's quite messy (in a constructive tone). I'll suggest a few approaches you can follow in an answer... – Leo Jan 14 '14 at 07:56
  • @Leo : U are welcome , if u have any ideas to render some server side values of the controls on the page after `Page_load()` i'll be grateful :) – Anyname Donotcare Jan 14 '14 at 08:12

8 Answers8

6
function GetServiceInformation(x) {

    $.ajax({
        type: "POST",
        url: "page.aspx/GetServiceInformation",
        data: "{'x':'" + x + "'}",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: on_sucess,
        error: on_error
    });
    function on_sucess(data, status) {

        alert(data);

    }
    function on_error(request, status, error) {

        alert(error);
    }

}

Sorry, if it doesn't work

Ram
  • 143,282
  • 16
  • 168
  • 197
anotherdie
  • 94
  • 3
  • How to call this method `GetServiceInformation(x)` ?? and what should i pass to the `x` param – Anyname Donotcare Jan 08 '14 at 08:35
  • you can call function GetServiceInformation(x) by javascript and you can send parameter x and recieve x in behind code – anotherdie Jan 09 '14 at 05:58
  • Could u check the question again please , i want to do that because i want to set some controls on the page after the pageload say `2s after the page load` – Anyname Donotcare Jan 09 '14 at 10:39
  • u can't set control in web method, if u want to set control u can set it in the function on_sucess and use jquery or javascript. – anotherdie Jan 10 '14 at 01:11
6

Answer Edit Based On Chat Discussion

First, thanks for clarifying your question. It was bit hard to understand the problem you were trying to solve. The reason? Because your code wasn't clear enough and that usually happens when there are design issues. That's effectively what your facing here a bit of a design issue. First, I'll point out some mistakes...

In this javascript function...

function GetInfo() {
        PageMethods.GetServiceInformation(this);
    }

this is NOT an instance of your page. So there's no use to make your page implement an interface...

public partial class AppMaster : Log, IInfo{}

and expect that a javascript call would page an instance of System.Web.UI.Page to your class (not to mention an implementation of the IInfo interface). You can blindly ditch this approach because it's a permanent design issue and it's not even going to work.

Now, if what you want is to serve the page, then do some further processing and finally send the results of this processing back to the client asynchronously using javascript/ajax you have a couple of approaches here:

  1. Using SignalR which is my favourite approach (but you already stated your solution doesn't meet the requirements to use SignalR)
  2. Using jQuery ajax which is also a very valid approach

Now, I'll explain the second approach

Using jQuery Ajax

Simply render the page as you would normally do in ASP.NET. Then on the client-side, when the page loads, make an ajax request to start processing the information you want to display. You can start the request as soon as the page loads to make the processing on the server

$(function(){
    $.ajax({
        type: 'POST',
        url: 'AppMaster.aspx/GetServiceInformation',
        data: "{}",
        contentType: 'application/json;charset=utf-8',
        dataType: 'json',
        success: function(d) {
            //load data received
            },
        error: function() {
            //process the error
            }
    });
});

In the success handler you need to load the values received from the ajax call on your web controls. Then change your IInfo interface to a concrete object in a separate code file. But, remember that this class should NOT hold any references whatsoever to your web controls

public class JSInfo
{
    string Inbox { get; set; }
    string Draft { get; set; }
    string New { get; set; }
    string Approved { get; set; }
    string archive { get; set; }
    string search { get; set; }
    string cand { get; set; }
    string pri { get; set; }
    string power { get; set; }
    string admin { get; set; }
    string help { get; set; }
    bool l_cand { get; set; }
    bool l_pri { get; set; }
    bool l_power { get; set; }
    bool l_admin { get; set; }

    string lb_ApprovedCount { get; set; }
    string lb_InboxCount { get; set; }
    string lb_archive { get; set; }
    string lb_DraftCount { get; set; }

}

then change your page method to...

[System.Web.Services.WebMethod]
public static JSInfo GetServiceInformation()
{
    //you need to get the emp_num from session

    //construct the JSInfo object
    JSInfo info = new JSInfo();

    //get the data from the database
    var data = UserTrans.GetInbox(int.Parse(emp_num), 0);

    //set the properties of the JSInfo...similar to the line below for each property...Draft, New, Approved, etc
    info.Inbox = data.Inbox;

    //return the object to the client
    return info;
}

Notice that you need to get the emp_num value from Session since you stated in the chat discussion that this value comes from a Session variable. Now, going back to the success handler of your jQuery ajax call which executes soon after the response is received back from the server. You will receive a json object in the handler parameter d with the properties of the JSInfo class that you just sent from the server. Then you set the controls on the page...

success: function(d) {
            $('#id_inbox_control').val(d.Inbox);
            $('#id_draft_control').val(d.Draft);
            $('#id_new_control').val(d.New);

            //and keep doing the same for the rest of the controls
        },

That should be a neater solution. Of coure, I cannot cover every single details here. But for sure you will get the idea. If not, let me know if I need to expand on something.

Community
  • 1
  • 1
Leo
  • 14,625
  • 2
  • 37
  • 55
  • Firstly : thank u so much for your great explanation.i think i can't use `SignalR` cuz i use framework 3.5 (visual studio 2008). So i try the second long way ,and plz could i ask u if i face any problem ? – Anyname Donotcare Jan 14 '14 at 09:14
  • 1
    Definitely...feel free to ask – Leo Jan 14 '14 at 09:21
  • `change your IInfo interface to a concrete object` what do y mean by this ? did u mean that i have to change it to a class rather than interface ? – Anyname Donotcare Jan 14 '14 at 09:22
  • Yes, change to a class so that the underlying serializer can easily serialize the object without further efforts on your part – Leo Jan 14 '14 at 09:32
  • ok should this class be in the same class page (in this case cuz it's nested it will be static autonatically) or out of my page class ,and in this case i'll not able to access my controls through . should this class to be like interface just definitions or with implementation like what exist in my question ? – Anyname Donotcare Jan 14 '14 at 10:54
  • 1
    No, don't do that. Define it as a `public` `class` outside of your page. This `class` should be as simple as possible, with automatic properties and it should NOT hold any reference to your any web controls. This does NOT need to access your web controls. Do you understand that? – Leo Jan 14 '14 at 11:22
  • Good i create my class and create my server side method `GetServiceInformation(JSInfo x)`. but i don't understand the following function `function getInboxInfo()` how this method will set the controls ,and `success:` should i call the JSON method ?? this point need more clarification please – Anyname Donotcare Jan 14 '14 at 12:23
  • I don't understand what do u mean by `jsonObj["Inbox"] = $('selector').val();` How can u read values from controls which are not set yet?! – Anyname Donotcare Jan 14 '14 at 12:38
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/45194/discussion-between-leo-and-just-name) – Leo Jan 14 '14 at 12:56
  • `How can u read values from controls which are not set yet?!` that's exactly what you are doing in your question!!! Can you actually state what exactly it is that you want? Right now, you're just all over the place!!!! – Leo Jan 14 '14 at 12:59
  • I debug the code and i find the web method returning the required data , but after that the labels still empty !! Does they lose their values !? – Anyname Donotcare Jan 14 '14 at 14:24
  • what are you doing in the success handler? – Leo Jan 14 '14 at 14:48
  • As u write : `success: function(d) { $('#lbl_InboxCount').val(d.lb_InboxCount); //and keep doing the same for the rest of the controls },` – Anyname Donotcare Jan 14 '14 at 15:12
  • you're kidding me, aint you? Have you got brain damage or what? – Leo Jan 14 '14 at 16:23
  • I can't believe how much time I have wasted – Leo Jan 14 '14 at 16:27
  • Never mind, I give up...read some tutorials mate and stop wasting people's time here. You can't assume anyone is going to write the whole project for you – Leo Jan 14 '14 at 16:57
  • This 's the first time i use page method , i'm sorry for wasting your time . anyway thank u so much for your help . – Anyname Donotcare Jan 14 '14 at 16:59
  • U don't need to hurt me ,I appreciate your help, and really thank u so much , i read some articles right now about how to call page method using jquery to fix my problem . – Anyname Donotcare Jan 14 '14 at 17:20
  • 1
    Seriously, you already have that working...i recommend you to read a tutorial about jQuery. I'm glad I could help but you have to realize that none of us can guide you an entire solution here for obvious reasons – Leo Jan 14 '14 at 17:29
  • I try to `alert (d.lb_InboxCount)` but undefined – Anyname Donotcare Jan 14 '14 at 17:32
  • Thanks for your effort :) although i still don't know what the wrong i have made . – Anyname Donotcare Jan 16 '14 at 13:19
3

If your page implements the interface, you don't have to pass it! In your c# code write:

this.l_power=true;

If you need to pass values from JavaScript to page method, define each property as a parameter and pass values to the page method:

[System.Web.Services.WebMethod]
public static string GetServiceInformation(int value1, string value2)
{
    l_power = value1;
    something = value2;
    return "some string to indicate the result of call";
}

And:

<script type ="text/javascript">
    var v1 = 15;
    var v2 = "some value";
    function GetInfo() {
        PageMethods.GetServiceInformation(v1, v2, success, fail);
    }
   window.onload = setTimeout("GetInfo()", 3000);
</script>

in which success and fail are the names of two JS functions that will be called after the request is completed. Note that a page method can return a string value to inform the client about what happened on the server.

Delphi.Boy
  • 1,199
  • 4
  • 17
  • 38
2

I can only think of one method.

You should somehow marshal the this object, and send it as parameter. I mean you should write a method that marshalls an object to equivalent json or xml, and POST that to your server.

I believe you can do it as you did above only through a clean API and compiler tool between C# and javascript to implement RPC just like GWT was written for java and javascript.

Siva Tumma
  • 1,695
  • 12
  • 23
2

Can you do a little test?

Declare a public class JSInfo: IInfo{} in your page code, and in your web method declare that parameter of yours as JSInfo.

As JSInfo implements IInfo, your program logic can work with it without any problem.

Just to let you know, your code does not work because you cannot serialize interfaces as they are not concrete types, if you think about it, interfaces have no real correlation in XML schema. There's no way to represent the data. Base classes will work however.

If you fill bad in declaring the JSInfo in the asp.net page class, then create a class called WebMethodsHelper and declare your JavaScript WebMethod Interfaces (Adaptors) there.

public class JSInfo: IInfo{
    private ControlsCollection controls;

    public JSInfo(ControlsCollection constrols){
        this.controls = controls
        FillObjects();
    }

    private void FillObjects(){
        //iterate through controls and extract you data to you 
        //class properties/fields
    }

    public void Update(ControlsCollection controls){
        this.controls=controls;
        FillObjects();
    }

    public void Update(JSInfo info, ControlsCollection controls){
        this.controls=controls;

        //populate your object based on info

        //then extract data from page controls
        FillObjects();
    }
}


public class MyPage: System.Web.UI.Page{

     protected void Page_Load(object sender, EventArgs e){
          if(!IsPostBack && Session["info_obj"])
               Session["info_obj"] = new JSInfo(this.Controls);
     }

     [System.Web.Services.WebMethod]
     public static string GetServiceInformation(JSInfo data)
     {
         JSInfo info = new JSInfo(this.Controls);
         info.Update(data);

         //or if you stored the info in the session
         JSInfo info = (JSInfo)Session["info_obj"];
         info.Update(this.Controls, data);
     }
}

The JSInfo is just to give your IInfo interface some structure so it can be serialized.

From JavaScript you should be able to call you page method like this:

<script type ="text/javascript"> 

function GetInfo() { 
     var info = new JSInfo();
     info.PropertyXPTO="something";

     PageMethods.GetServiceInformation(info, onSuccess, onError);
} 

function onSuccess(result) {
    alert(result);
}

function onError(result) {
    alert('error: ' + result);
}

window.addEventListener("load", function(){
   setTimeout("GetInfo()", 10 * 1000); 
}, false);

</script>

Not that you should have a ScriptManager at the top of your page

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

The ScriptManager is responsible for giving you the PageMethods class in the JavaScript, along with other things.

Also, confirm the following:

  • The page method must have the System.Web.Services.WebMethod attribute. [WebMethod]
  • The page method must be public. [WebMethod] public ...
  • The page method must be static. [WebMethod] public static ...
  • The page method must be defined on the page (either inline or in the code-behind). It cannot be defined in a control, master page, or base page.
  • The ASP.NET AJAX Script Manager must have EnablePageMethods set to true.
João Pinho
  • 3,725
  • 1
  • 19
  • 29
  • I do this `` but i get javascript error `too much recursion error` – Anyname Donotcare Jan 09 '14 at 10:37
  • @just_name Please check my answer again... if you got any error, report them back to me, here. Thanks. – João Pinho Jan 09 '14 at 11:28
  • The problem i can't implement the interface in your class,because i set controls like this: `public string Inbox { get { return hpl_Inbox.NavigateUrl;//hyper link } set { hpl_Inbox.NavigateUrl = value; } }` So i implement the interface in the same page `public partial class AppMaster : Log, IInfo //My page` I can't implement the interface in your class `public class JSInfo: IInfo{}` cuz i have to implement controls in the page can't be accessed through that class – Anyname Donotcare Jan 09 '14 at 12:13
  • Get the following error : `Cannot access a non-static member of outer type 'AppMaster' via nested type 'AppMaster.JSInfo'` – Anyname Donotcare Jan 09 '14 at 12:27
  • Is the JSInfo declared public class? If so, this is odd, but create a class inheriting from interface IInfo (and delete that inner class) and try it again. Maybe the compiler is complaining about the inner class, super odd. – João Pinho Jan 09 '14 at 12:45
  • yeah in c# nested classes are static by default :( http://stackoverflow.com/a/5393472/418343 – Anyname Donotcare Jan 09 '14 at 12:47
  • where to put this class , i wanna this class to access my controls on the page. – Anyname Donotcare Jan 09 '14 at 12:48
  • You can put it anywhere, just create a class .cs with the name JSInfo inheriting from IInfo a store this type of classes inside a Folder called 'JScriptAdapters', or something you like that make logic in your project. – João Pinho Jan 09 '14 at 19:26
  • I have to put this class in the same page class,cuz i want to access some controls like (labels, links) on the page !! – Anyname Donotcare Jan 10 '14 at 10:03
  • Why don't you initialize the class with Controls Collection of the page then? – João Pinho Jan 10 '14 at 11:33
  • I did you a little example explaining what I meant. – João Pinho Jan 10 '14 at 11:49
  • `ControlsCollection` unknown !! what's the name space , i can't use the following name space `using System.Web.UI.ControlCollection`. my framework is 3.5 – Anyname Donotcare Jan 12 '14 at 07:54
2
function GetServiceInformation(x) {
$.ajax({
    type: "POST",
    url: "page.aspx/GetServiceInformation",
    data:  x, //Attention: there is no {}
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: on_sucess,
    error: on_error
});
function on_sucess(data, status) {
    alert(data);
}
function on_error(request, status, error) {
    alert(error);
}
}

And then

<script type ="text/javascript">

function GetInfo() {
var myInfo = {
        Inbox: "",
        Draft: "",
        New: "",
        l_cand: ""
        ......//Attention, you should make this class corresponding to your server class IInfo
    };
    PageMethods.GetServiceInformation(myInfo);
}
window.onload = setTimeout("GetInfo()", 3000);

Referred to @anotherdie. And tell you how to transfer "X"

CLoren
  • 298
  • 2
  • 5
  • 10
2

In your .js

function GetInfo() { 
    var parameter = {};
    parameter.name = "test";
    parameter.id = 123;
    parameter.state = true;

    PageMethods.GetServiceInformation(parameter, 
            function (res) {
                if (res == true) {
                     //do some
                     alert("ok");
                   } else {
                     //do some
                     alert("bad");       
                   }
            }, function(err){
               alert("ERROR: "+err._message);
            });
}

in your apsx.cs (you can return a string, a list, a bool, an int or a json object //for json use json.net http://james.newtonking.com/json) for this i'll return a bool.

using System.Web.Services;

[WebMethod]
public static bool GetServiceInformation(ClassData parameters)
{
  try
  {
    //do some
    return true;
  }    
  catch(Exception ex)
  {
     return false;
  }
}

in a interface ClassData .cs

   public string name { get; set; }
   public int id { get; set; }
   public bool state { get; set; }

   public ClassData(){}

   public ClassData(string _name, int _id, bool _state)
   {
     this.name = _name;
     this.id= _id;
     this.state = _state;
   }
0

I do the following :

Create New Page and called it : Counts.aspx

 protected void Page_Load(object sender, EventArgs e)
        {

                        emp_num = int.Parse(Session["empnum"].ToString());
                        Thread.Sleep(3000);
                        string res = GetCounts(emp_num);
                        Response.Write(res);

        }
        /***********************************************************************************************/
        protected string GetCounts(int empNum)
        {

            string outbox = UserTransaction.getoutboxCount(empNum, 0);
            string inbox = UserTransaction.getinboxCount(empNum, 0);
            string archive = UserTransaction.getarchivecount(empNum, 0);
            string draft = UserTransaction.getdraftcount(empNum, 0);
            return outbox + "~" + inbox + "~" + archive + "~" + draft + "~";

        }

and in my main page :

 <script type="text/javascript">

        function loadXMLDoc() {
            var xmlhttp;
            if (window.XMLHttpRequest) {
                xmlhttp = new XMLHttpRequest();
            }
            else {
                xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
            }
            xmlhttp.onreadystatechange = function() {
                if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                    var split = xmlhttp.responseText.split('~');

                    var outbox = split[0];
                    var inbox = split[1];
                    var archive = split[2];
                    var draft = split[3];
                    document.getElementById("lbl_DraftCount").innerHTML = draft;
                    document.getElementById("lbl_InboxCount").innerHTML = inbox;
                    document.getElementById("lbl_ApprovedCount").innerHTML = outbox;
                    document.getElementById("lbl_archive").innerHTML = archive;
                }
            }
            xmlhttp.open("GET", "Counts.aspx", true);
            xmlhttp.send();
        }
        loadXMLDoc();


    </script>
Anyname Donotcare
  • 11,113
  • 66
  • 219
  • 392