如何通过JavaScript事件调用带参数的页面方法?

16

我在我的 .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);
}

现在我想通过一个 JavaScript 方法作为页面方法调用这个方法,但它不起作用。

<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>

我的.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
 }

我的界面:

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; }

    }

2
你正在JavaScript中将this传递给页面方法。虽然你在C#代码中有一个接口,但无法通过这种方式实现。请告诉我们更多关于你想要做什么的信息,以便我们提供帮助。 - Delphi.Boy
这个问题有点疯狂。为什么需要使用Page Methods和ajax来设置控件?难道不能直接从JavaScript中设置控件吗?你想要设置哪些控件?为什么要这样做?能否提供一些背景信息,而不是展示一些明显在重复造轮子的疯狂代码? - Leo
@Leo:我不是在试图重新发明轮子。我想做的是设置一些控件(标签、超链接等),这些控件的值来自服务器端,在“页面加载”后进行计算需要很长时间,所以我不希望用户等待那些分析值,我希望它们在页面加载事件后在后台呈现,因此我尝试使用ajax来实现我的目标,如果你有任何想法,请告诉我,我会非常感激 :) - Anyname Donotcare
1
@just_name 抱歉,别误会了...我只是想从你那里挤出一些信息,因为我还不清楚你为什么要在实现中走这条路。它相当混乱(以建设性的口吻)。我会在回答中建议几种你可以遵循的方法... - Leo
@Leo:不客气,如果您有任何想法,在Page_load()之后呈现页面控件的一些服务器端值,我会非常感激 :) - Anyname Donotcare
显示剩余6条评论
8个回答

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);
    }

}

抱歉,如果它不起作用


如何调用此方法 GetServiceInformation(x)?我应该传递什么给 x 参数? - Anyname Donotcare
你可以通过JavaScript调用函数GetServiceInformation(x),并且可以发送参数x并在后台代码中接收x。 - anotherdie
请再检查一下问题,因为我想在页面加载后设置一些控件,比如“页面加载后2秒钟”。 - Anyname Donotcare
如果你想设置控件的话,不能在Web方法中进行设置,而是需要在on_success函数中使用jQuery或JavaScript来进行设置。 - anotherdie

6

基于聊天讨论的答案修改

首先,感谢您澄清问题。有点难理解您试图解决的问题。原因是什么?因为您的代码不够清晰,这通常发生在存在设计问题时。这实际上是您在此处面临的一些设计问题。首先,我将指出一些错误...

在这个JavaScript函数中...

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

this 不是您页面的实例,因此没有必要使您的页面实现接口...

public partial class AppMaster : Log, IInfo{}

我希望您能将一个javascript调用页面的实例System.Web.UI.Page转化为您的类(更不用说IInfo接口的实现),但是这种方法有一个永久性的设计问题,并且甚至无法使用。如果您想服务于该页面并进行一些后续处理,最后使用javascript/ajax异步地将这个处理的结果发送回客户端,那么您有以下几种方法:
1. 使用 SignalR(这是我最喜欢的方法,但是您已经说过您的解决方案不能满足使用 SignalR的要求)。 2. 使用 jQuery ajax,这也是一个非常有效的方法。
现在,我将解释第二种方法。
使用jQuery Ajax
简单地按照您通常在ASP.NET中所做的那样渲染页面。然后,在客户端加载页面时,发起一个ajax请求来开始处理您想要显示的信息。您可以在页面加载时立即开始请求以便服务器上的处理。
$(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
            }
    });
});

在成功处理程序中,您需要将从ajax调用接收到的值加载到Web控件上。然后,在单独的代码文件中将您的接口更改为具体对象。但是,请记住,此类不应保留任何与您的Web控件有关的引用。
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; }

}

那么将你的页面方法更改为...
[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;
}

请注意,您需要从Session中获取emp_num的值,因为您在聊天讨论中提到该值来自Session变量。现在回到您的jQuery ajax调用的成功处理程序,该处理程序在从服务器接收响应后不久执行。您将在处理程序参数d中接收一个json对象,该对象具有刚刚从服务器发送的JSInfo类的属性。然后您可以设置页面上的控件...
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
        },

这应该是一个更加整洁的解决方案。当然,我不能在这里涵盖每一个细节。但是肯定你会理解的。如果没有,请告诉我是否需要对某些内容进行扩展。


1
绝对没问题,随时问吧。 - Leo
是的,将其更改为类,这样底层序列化程序就可以轻松地对对象进行序列化,而无需您进一步努力。 - Leo
这个类应该放在同一个类页面中吗?(因为它是嵌套的,所以它会自动变成静态)。还是应该放在我的页面类之外,在这种情况下,我将无法通过...访问我的控件。 这个类应该像接口一样只有定义,还是像我的问题中存在的那样带有实现? - Anyname Donotcare
1
不,不要这样做。将其定义为一个位于页面之外的“public”类。这个类应该尽可能简单,使用自动属性,并且不应该持有任何对你的任何Web控件的引用。它不需要访问你的Web控件。你明白吗? - Leo
1
说真的,你已经有这个工作了...我建议你阅读一篇关于jQuery的教程。我很高兴能帮助你,但你必须意识到,由于明显的原因,我们中没有人可以在这里为你提供完整的解决方案。 - Leo
显示剩余16条评论

3
如果您的页面实现了该接口,那么您就不需要传递它!在您的c#代码中编写:
this.l_power=true;

如果你需要从JavaScript传递值到页面方法中,需要将每个属性定义为参数,并将值传递给页面方法。
[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";
}

同时:

<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>

其中 successfail 是两个JS函数的名称,它们将在请求完成后被调用。请注意,页面方法可以返回一个字符串值,以通知客户端服务器发生了什么。


谢谢,但我希望传递当前实例而不是变量,因为在我的方法中,我设置了一些属性,就像这样: info.lb_DraftCount = TransDAL.Draft_Count(int.Parse(emp_num), 0); - Anyname Donotcare
这是一个静态方法。你不能使用this - John Saunders
1
@JohnSaunders 谢谢。我的错。再说一遍,我坚持认为这种方法行不通。他应该采取另一种方式。 - Delphi.Boy

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);
}
}

然后

<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);

参考@anotherdie并告诉你如何传输“X”


2
在你的 .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);
            });
}

在你的apsx.cs文件中(你可以返回一个字符串、列表、布尔值、整数或JSON对象//对于JSON使用json.net http://james.newtonking.com/json),我将返回一个布尔值。
using System.Web.Services;

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

在一个接口 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;
   }

2

你能做一个小测试吗?

在你的页面代码中声明一个 public class JSInfo: IInfo{},并在你的Web方法中将参数声明为JSInfo。

由于JSInfo实现了IInfo,所以你的程序逻辑可以毫无问题地使用它。

需要注意的是,你的代码不能工作,因为你不能序列化接口,因为它们不是具体类型,如果你考虑一下,接口在XML模式中没有真正的相关性。基类将会起作用。

如果在asp.net页面类中声明JSInfo让你感到困扰,那么创建一个名为WebMethodsHelper的类,在其中声明你的JavaScript WebMethod接口(适配器)。

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);
     }
}

JSInfo仅是为了给您的IInfo接口提供一些结构,以便它可以被序列化。

从JavaScript中,您应该能够像这样调用您的页面方法:

<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>

并不是说你应该在页面顶部放置ScriptManager

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

ScriptManager负责在JavaScript中提供PageMethods类以及其他内容。

另外,请确认以下内容:

  • 页面方法必须具有System.Web.Services.WebMethod属性。[WebMethod]
  • 页面方法必须是公共的。[WebMethod] public ...
  • 页面方法必须是静态的。[WebMethod] public static ...
  • 页面方法必须在页面上定义(可以是内联或在代码后台)。它不能在控件、主控页或基本页面中定义。
  • ASP.NET AJAX Script Manager必须将EnablePageMethods设置为true。

我写了这段代码:但是我遇到了 JavaScript 错误 too much recursion error - Anyname Donotcare
我遇到的问题是无法在您的类中实现接口,因为我设置了如下这样的控件:public string Inbox { get { return hpl_Inbox.NavigateUrl;//超链接 } set { hpl_Inbox.NavigateUrl = value; } }所以我在同一页中实现了接口:public partial class AppMaster : Log, IInfo //我的页面我不能在您的类 public class JSInfo: IInfo{} 中实现接口, 因为我必须在页面中实现不可通过该类访问的控件。 - Anyname Donotcare
获取以下错误: 无法通过嵌套类型“AppMaster.JSInfo”访问外部类型“AppMaster”的非静态成员 - Anyname Donotcare
JSInfo是否声明为公共类?如果是,这很奇怪,但是创建一个继承接口IInfo的类(并删除那个内部类),然后再尝试一下。也许编译器正在抱怨内部类,非常奇怪。 - João Pinho
ControlsCollection未知!!这是什么命名空间,我不能使用以下命名空间using System.Web.UI.ControlCollection。我的框架是3.5。 - Anyname Donotcare
显示剩余7条评论

2
我只能想到一种方法。
你应该以某种方式编排这个对象,并将其作为参数发送。我的意思是,你应该编写一个方法,将一个对象编排成相等的json或xml,并将其POST到你的服务器。
我相信你可以通过一个干净的API和编译器工具,实现C#和javascript之间的RPC,就像GWTjava和javascript编写的那样。

0
我做了以下事情:
创建一个新页面并称为: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 + "~";

        }

而在我的主页上:

 <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>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接