• ASP.NET AJAX(4)__客户端访问WebService


    服务器端释放WebService方法

    • 编写一个普通的WebService
    • 为WebService类添加自定义的属性标记__ScriptServiceAttribute
    • 释放WebService方法

                      __访问级别为Public

                      __使用WebServiceAttribute进行标记

    • 为页面中的ScriptManager引入asmx文件

    客户端访问WebService

    1. [Namespaces.]ClassName.MethodName
    2. 依次传入参数
    3. 传入一个方法作为成功后的回调函数(即使没有返回值)
    一个简单的访问WebService示例

             首先创建一个WevService名为WebServiceFoundation,代码如下

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    
    /// <summary>
    ///WebServiceFoundation 的摘要说明
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    //若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。 
    [System.Web.Script.Services.ScriptService]
    public class WebServiceFoundation : System.Web.Services.WebService
    {
        [WebMethod]
        public int GetRandom()
        {
            return new Random(DateTime.Now.Millisecond).Next();
        }
    
        [WebMethod]
        public int GetRangeRandom(int minValue, int maxValue)
        {
            return new Random(DateTime.Now.Millisecond).Next(minValue, maxValue);
        }
    }
     

    然后,创建一个页面名为WebServiceFoundation,添加ScriptManager,在它内部添加如下代码

    <asp:ScriptManager ID="ScriptManager1" runat="server">
                <Services>
                    <asp:ServiceReference Path="~/Demo03/WebServiceFoundation.asmx" />
                </Services>
            </asp:ScriptManager>

    这样,我们就在客户端添加一些关于这个WebService的代码

    接下来,我们就在客户端调用这个WebService的GetRandom方法

    在页面中添加如下代码

    <input type="button" value="Get Random" onclick="getRandom()" />
            <input type="button" value="Get Range Random" onclick="getRandom(100,500)" />
            
            <script language="javascript" type="text/javascript">
    
                function getRandom(minValue, maxValue) {
                    if (arguments.length != 2) {//方法的参数个数,当不等于2时
                        WebServiceFoundation.GetRandom(getRandomSucceeded); //getRandomSucceeded是访问WebService的回调函数
                    }
                    else {
                        WebServiceFoundation.GetRangeRandom(minValue, maxValue,getRandomSucceeded);
                    }
                }
                function getRandomSucceeded(result) {
                    alert(result);
                }
            </script>

    这样,我们就成功调用了这个WebService,当点击"Get Random"按钮时,弹出一个普通随机数,在单击"Get Range Random"按钮时,弹出一个介于100到500之间的随机数

    客户端访问PageMethod

    • 只能在aspx页面中定义
    • 只能是public static方法
    • 使用WebMethodAttribute标记
    • ScriptManager的EnablePageMethod设置为true
    • 通过pageMethods.MethodName进行访问
    一个访问PageMethod的示例

    创建一个页面,页面代码如下

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true">
            </asp:ScriptManager>
            
            <input type="button" value="Get Current Time" onclick="getCurrentTime()" />
            
            <script language="javascript" type="text/javascript">
                function getCurrentTime() {
                    
                    PageMethods.GetCurrentTime(getCurrentTimeSucceeded);
                }
                function getCurrentTimeSucceeded(result) {
                    alert(result);
                }
            </script>
        </form>
    </body>
    </html>
    

    后台代码中添加

    [WebMethod]
        public static DateTime GetCurrentTime()
        {
            return DateTime.Now;
        }

    主要,要引入using System.Web.Services命名空间

    这样,我们就可以在点击按钮后访问PageMethod得到一个当前时间啦

    错误处理

    • 调用时,可以提供一个接收错误的回调函数
    • 包括超时和服务器端抛出的异常
    • 超时只能设置在WebService级别
    • 由Sys.Net.WebServiceError提供

          一个错误处理的示例

    创建一个WebService添加如下代码

    [WebMethod]
        public int GetDivision(int a, int b)//这里我们会使用它抛出一个经典的除0错误
        {
            return a / b;
        }
    
        [WebMethod]
        public int Timeout()//调用这个方法是,我们会首先设置它等待2秒,造成一个超时
        {
            System.Threading.Thread.Sleep(5000);
            return 0;
        }

    然后创建一个页面,调用这个WebService

    <asp:ScriptManager ID="ScriptManager1" runat="server">
                <Services>
                    <asp:ServiceReference Path="~/Demo03/ErrorHandling.asmx" />
                </Services>
            </asp:ScriptManager>
            
            <input type="button" value="Get Division" onclick="getDivision(5,0)" />
            <input type="button" value="TimeOut" onclick="timeout()" />
            <script language="javascript" type="text/javascript">
    
                function getDivision(a, b) {
                    ErrorHandling.GetDivision(a, b, null, failedCallback);
                }
    
                function timeout() {
                    ErrorHandling.set_timeout(2000);
                    ErrorHandling.Timeout(null, failedCallback);
                }
    
                function failedCallback(error) {
                    var message = String.format("Timeout:{0}\n Message:{1}\n Exception Type:{2}\n StackTrace:{3}", error.get_timedOut(), error.get_message(), error.get_exceptionType(), error.get_stackTrace());
                    alert(message);
                }
            </script>

    这时,我们点击按钮,就可以看到一些错误信息了,实际应用中,我们可以利用这些信息,在页面上相应的做一些提示

    复杂数据类型使用基础

    首先,定义一个Employee类

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    /// <summary>
    ///Employee 的摘要说明
    /// </summary>
    public class Employee
    {
        private string _firstname;
        private string _lastname;
        private string _title;
    
        public Employee(string firstname, string lastname, string title)
        {
            this._firstname = firstname;
            this._lastname = lastname;
            this._title = title;
        }
        public Employee() { }
        public string FirstName
        {
            get { return this._firstname; }
            set { this._firstname = value; }
        }
        public string LastName
        {
            set { this._lastname = value; }
            get { return this._lastname; }
        }
        public string Title
        {
            get { return this._title; }
        }
    
        public int Salary { get; set; }
    
        public string FullName
        {
            get
            {
                return this.FirstName + this.LastName;
            }
        }
        public static implicit operator string(Employee employee)
        {
            return employee.FullName;
        }
    }
    

    然后创建一个WebService

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    
    /// <summary>
    ///ComplexType 的摘要说明
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    //若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。 
    [System.Web.Script.Services.ScriptService]
    public class ComplexType : System.Web.Services.WebService
    {
    
        [WebMethod]
        public Employee DoubleSalary(Employee employee)
        {
            employee.Salary *= 2;
            return employee;
        }
    
        [WebMethod]
        public List<int> Reverse(List<int> list)
        {
            list.Reverse();
            return list;
        }
    
        [WebMethod]
        public IDictionary<string, Employee> GetEmployee()
        {
            Dictionary<string, Employee> result = new Dictionary<string, Employee>();
            Employee emp1 = new Employee();
            emp1.FirstName = "bai";
            emp1.LastName = "yulong";
            emp1.Salary = 2000;
            result[emp1.FullName] = emp1;
    
            Employee emp2 = new Employee();
            emp2.FirstName = "xiao";
            emp2.LastName = "yaojian";
            emp2.Salary = 4000;
            result[emp2.FullName] = emp2;
    
            return result;
        }
        
    }
    
    

    然后创建一个页面,使用他们,首先在页面中添加ScriptManager,引入上面创建的WebService,添加如下代码

    <input type="button" value="Double Salary" onclick="doubleSalary()" />
            <input type="button" value="Reverse" onclick="reerse([1,2,3,4,5])" />
            <input type="button" value="Get Employee" onclick="getEmploee()" />
            <script language="javascript" type="text/javascript">
                function doubleSalary() {
                    var employee = new Object();
                    employee.FirstName = "bai";
                    employee.LastName = "yulong";
                    employee.Salary = 1000;
                    ComplexType.DoubleSalary(employee, doubleSalarySucceeded);
                }
    
                function doubleSalarySucceeded(result) {
                    var message = String.format("FirstName:{0}\nLastName:{1} \nFullName:{2} \nSalary:{3}", result.FirstName, result.LastName, result.FullName, result.Salary);
                    alert(message);
                }
    
                function reerse(array) {
                    ComplexType.Reverse(array, function(result) { alert(result); });
                }
    
                function getEmploee() {
                    ComplexType.GetEmployee(getEmployeeSucceeded);
                }
    
                function getEmployeeSucceeded(result) {
                    for (var name in result) {
                        alert(name + ":" + result[name].Salary);
                    }
                }
            </script> 

    这时,我们点击"Double Salary"按钮,就可以调用WebService上的DoubleSalary方法,使工资翻倍啦

    如果我们这时用HTTP Watch看的话,就可以看见我们发送的是一个JSON字符串,返回的同样是一个JSON字符串,但是他在前面使用__type指定了一个Employee类型

    其他的两个方法,演示的就是实现了IList和IDictionary接口的类型的使用方式,这里使用一些工具,就可以很明显的看到他们在发送和接受数据中的方式

    客户端代理的使用细节

    • 函数调用的完整签名-Invoke(arg1,arg2,….,onSucceeded,onFailed,userContext)
    • 回调函数完整签名-onSucceeded(result,userContext,methodName),onFailed(error,userContext,methodName)
    • WebService级别默认属性:timtout,defaultUserContext,defaultSucceededCallBack,defaultFailedCallBack

    生成复杂参数类型的客户端代理

    • 使用GenerateScriptTypeAttribute标记要生成的代理的参数类型
    • 可以标记在类,接口,以及方法上
    • 生成的代理中将包括客户端类型的代理
    • 调用方法时可以创建“具体类型”(使用提供的默认构造函数)

             一个示例,演示GenerateScriptTypeAttribute标记

              首先创建一个类Color

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    /// <summary>
    ///Color 的摘要说明
    /// </summary>
    public class Color
    {
        public byte Red;
        public byte Blue;
        public byte Green;
    
    
        public Color()
        {
    
        }
    
        public Color(byte red, byte green, byte blue)
        {
            this.Red = red;
            this.Blue = blue;
            this.Green = green;
        }
    }

    然后创建一个ColorService.asmx

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    using System.Web.Script.Services;
    
    /// <summary>
    ///ColorService 的摘要说明
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    //若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。 
    [System.Web.Script.Services.ScriptService]
    public class ColorService : System.Web.Services.WebService
    {
    
        [WebMethod]
        [GenerateScriptType(typeof(Color))]//这样就会在客户端生成一个复杂类型的代理
        public Color Reverse(Color color)
        {
            return new Color((byte)(255 - color.Red), (byte)(255 - color.Green), (byte)(255 - color.Blue));
        }
        
    }
    

    这样在页面中,使用这个WebService的时候,就会生成一个Color类型的代理,然后我们创建页面引入这个WebService

    在页面中添加如下代码

    <input type="button" value="Reserve Color" onclick="ReverseColor()" />
            
            <script type="text/javascript" language="javascript">
                function ReverseColor() {
                    //var color = { "Red": 50, "Green": 100, "Blue": 200 };
                    var color = new Color();
                    color.Red = 50;
                    color.Green = 100;
                    color.Blue = 150;
                    
                    ColorService.Reverse(color, onSucceeded);
                }
    
                function onSucceeded(result) {
                    alert(String.format("Red:{0}\nGreen:{1}\nBlue:{2}",result.Red,result.Green,result.Blue));
                }
            </script>

    我们看到,这里我们就可以直接创建一个Color类型进行使用了

    再写一个示例,演示客户端代理的作用

    首先创建一个类文件Staff

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    /// <summary>
    ///Staff 的摘要说明
    /// </summary>
    public abstract class Staff
    {
        private int _Years;
    
    
        public int Years
        {
            get { return this._Years; }
            set { this._Years = value; }
        }
    
        public string RealStatus
        {
            get { return this.GetType().Name; }
        }
    
        public abstract int CaloulateSalary();
    }
    
    public class Intern : Staff
    {
        public override int CaloulateSalary()
        {
            return 2000;
            //throw new NotImplementedException();
        }
    }
    
    public class Vendor : Staff
    {
        public override int CaloulateSalary()
        {
            return 5000 + 1000 * (Years - 1);
            //throw new NotImplementedException();
        }
    }
    
    public class FulltimeEmployee : Staff
    {
        public override int CaloulateSalary()
        {
            return 15000 + 2000 * (Years - 1);
            //throw new NotImplementedException();
        }
    }
    

    然后创建一个StaffService.asmx

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    using System.Web.Script.Services;
    
    /// <summary>
    ///StaffService 的摘要说明
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    //若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。 
    [System.Web.Script.Services.ScriptService]
    public class StaffService : System.Web.Services.WebService 
    {
        [WebMethod]
        [GenerateScriptType(typeof(Vendor))]
        [GenerateScriptType(typeof(Intern))]
        [GenerateScriptType(typeof(FulltimeEmployee))]
        public string CalculateSalary(Staff staff)
        {
            return "I'm " + staff.RealStatus + ",my  salary is" + staff.CaloulateSalary() + ".";
        }
    }

    然后创建页面

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager runat="server" ID="sm">
                <Services>
                    <asp:ServiceReference Path="~/Demo03/StaffService.asmx" />
                </Services>
            </asp:ScriptManager>
            
            <div>Ysers:<input type="text" id="txtYears" /></div>
            <div>
                Status:
                <select id="comboStatus" style="150px;">
                    <option value="Intern">Intern</option>
                    <option value="Vendor">Vendor</option>
                    <option value="FulltimeEmployee">FTE</option>
                </select>
            </div>
            <input type="button" value="Calculate!" onclick="calculateSalary()" /><br /><hr />
            <b>Result:</b>
            <div id="result"></div>
            
            <script language="javascript" type="text/javascript">
                function calculateSalary() {
                    var emp = new Object();
                    emp.__type = $get("comboStatus").value;
                    
                    emp.Years = parseInt($get("txtYears").value, 10);
    
                    StaffService.CalculateSalary(emp, onSucceeded);
                }
    
                function onSucceeded(result) {
                    $get("result").innerHTML = result;
                }
            </script>
        </form>
    </body>
    </html>

    这样我们在输入一个工作年数,再选择一个员工类型后,点击"Calculate!"按钮, 就可以计算出他们的工资啦

    这就是一个客户端代理做出多态效果的示例

    使用JavaScriptConverter

    • 复杂类型作为返回值时可能会出现为题__循环引用
    • 解决方案___使用自定义的数据类型封装复杂类型,在web.config中定义converter

              一个使用JavaScriptConverter的示例

    首先我们创建一个DataTableService.asmx

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    using System.Web.Script.Services;
    using System.Data;
    
    /// <summary>
    ///DataTableService 的摘要说明
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    //若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。 
    [ScriptService]
    public class DataTableService : System.Web.Services.WebService 
    {
        [WebMethod]
        public DataTable GetDataTable()
        {
            DataTable dt = new DataTable();
            dt.Columns.Add(new DataColumn("ID",typeof(int)));
            dt.Columns.Add(new DataColumn("Text", typeof(string)));
    
            Random random = new Random(DateTime.Now.Millisecond);
            for (int i = 0; i < 10; i++)
            {
                dt.Rows.Add(i, random.Next().ToString());
            }
    
            return dt;
        }
    }
    
    

    然后创建一个页面使用它

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager ID="ScriptManager1" runat="server">
                <Services>
                    <asp:ServiceReference Path="~/Demo9/DataTableService.asmx" />
                </Services>
            </asp:ScriptManager>
            
            <input type="button" value="Get DataTable" onclick="getDataTable()" />
            
            <div id="result"></div>
            
            <script language="javascript" type="text/javascript">
                function getDataTable() {
                    
                    DataTableService.GetDataTable(onSucceeded, onFailed);
                }
    
                function onSucceeded(result) {
                    //alert(result);
                    var sb = new Sys.StringBuilder("<table border='1'>");
                    sb.append("<tr><td>ID</td><td>TEXT</td></tr>");
                    for (var i = 0; i < result.rows.length; i++) {
                        sb.append(String.format("<tr><td>{0}</td><td>{1}</td><tr>", result.rows[i].ID, result.rows[i].Text));
    
                    }
                    sb.append("</table>");
                    $get("result").innerHTML = sb.toString();
                }
                
                function onFailed(error) {
                    alert(error.get_message());
                }
            </script>
        </form>
    </body>
    </html>
     

    这时,我们点击按钮时候,会弹出一个循环引用的错误提示,接下来我们就要解决它,首先在电脑中安装ASP.NET 2.0 AJAX Futures January CTP,然后找到里面的Microsoft.Web.Preview.dll,把它复制到当前项目的Bin目录下,然后在web.config的configuration中增加如下内容

    <system.web.extensions>
        <scripting>
          <webServices>
            <authenticationService enabled="true" requireSSL="false"/>
            <profileService enabled="true"/>
            <jsonSerialization>
              <converters>
                <add name="DataSetConverter" type="Microsoft.Web.Preview.Script.Serialization.Converters.DataSetConverter,Microsoft.Web.Preview"/>
                <add name="DataRowConverter" type="Microsoft.Web.Preview.Script.Serialization.Converters.DataRowConverter,Microsoft.Web.Preview"/>
                <add name="DataTableConverter" type="Microsoft.Web.Preview.Script.Serialization.Converters.DataTableConverter,Microsoft.Web.Preview"/>
              </converters>
            </jsonSerialization>
          </webServices>
        </scripting>
      </system.web.extensions>

    这样,在使用DataSet等这些数据类型作为客户端复杂数据类型时,系统就会自动寻找这段jsonSerialization,对它进行转换

    这时我们再刷新页面,点击按钮,就得到了我们预期的效果

    定义一个JavaScriptConverter

    • 定义一个Converter继承JavaScriptConverter类
    • 实现SupportedTypes
    • 实现Serialize方法用于序列化复杂数据
    • 实现Deserizlize方法用于反序列化复杂数据
    • 在web.config中注册该Converter

           一个自定义的JavaScriptConverter示例

    首先定义一个类文件BoyAndGirl.cs

    using System;
    
    
    public class Boy
    {
        public string Name;
        public Girl GirlFriend;
    }
    
    
    public class Girl
    {
        public string Name;
        public Boy BoyFriend;
    }

    然后创建WebService名为BoyGirlService.asmx

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    using System.Web.Script.Services;
    using System.Diagnostics;
    
    /// <summary>
    ///BoyGirlService 的摘要说明
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    //若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。 
    [ScriptService]
    public class BoyGirlService : System.Web.Services.WebService
    {
        [WebMethod]
        public Boy GetBoyWithGirlFriend()
        {
            Boy boy = new Boy();
            boy.Name = "xiaoyaojian";
    
            Girl girl = new Girl();
            girl.Name = "have not";
    
            boy.GirlFriend = girl;
            girl.BoyFriend = boy;
            return boy;
        }
    
        [WebMethod]
        public string SetBoyWithGirlFriend(Boy boy)
        {
            Debug.Assert(boy == boy.GirlFriend.BoyFriend);
    
            return String.Format("It's {0},his girlfriend is {1}", boy.Name, boy.GirlFriend.Name);
        }
    }

    然后在页面中使用

    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager ID="ScriptManager1" runat="server">
                <Services>
                    <asp:ServiceReference Path="~/Demo03/BoyGirlService.asmx" />
                </Services>
            </asp:ScriptManager>
            
            <input type="button" value="Get Boy" onclick="getBoy()" />
            <input type="button" value="Set Boy" onclick="setBoy()" />
            
            <script language="javascript" type="text/javascript">
                function getBoy() {
                    BoyGirlService.GetBoyWithGirlFriend(onGetBoySucceeded, onFailed);
                }
    
                function setBoy() {
                    var boy = new Object();
                    boy.Name = "xiaoyaojian";
                    var girl = new Object();
                    girl.Name = "have not";
                    boy.GirlFriend = girl;
    
                    BoyGirlService.SetBoyWithGirlFriend(boy, onSetBoySucceeded, onFailed);
                }
    
                function onGetBoySucceeded(result) {
                    alert(String.format("It's {0},his girlfriend is {1}",result.Name,result.GirlFriend.Name));
                }
    
                function onFailed(error) {
                    alert(error.get_message());
                }
    
                function onSetBoySucceeded(result) {
                    alert(result);
                }
            </script>
        </form>
    </body>
    </html>

    这时,因为类中有一个循环引用,所以程序会报错,接下来,我们创建一个类BoyConverter继承JavaScriptConverter

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Script.Serialization;
    
    /// <summary>
    ///BoyConverter 的摘要说明
    /// </summary>
    public class BoyConverter:JavaScriptConverter
    {
        public BoyConverter()
        {
            //
            //TODO: 在此处添加构造函数逻辑
            //
        }
    
        public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
        {
            //throw new NotImplementedException();
            Boy boy = new Boy();
            
            boy.Name = (string)dictionary["Name"];
            boy.GirlFriend = serializer.ConvertToType<Girl>(dictionary["GirlFriend"]);
            boy.GirlFriend.BoyFriend = boy;
    
            return boy;
        }
    
        public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
        {
            //throw new NotImplementedException();
            Boy boy = (Boy)obj;
            IDictionary<string, object> result = new Dictionary<string, object>();
    
            result["Name"] = boy.Name;
    
            boy.GirlFriend.BoyFriend = null;
            result["GirlFriend"] = boy.GirlFriend;
    
            return result;
        }
    
        public override IEnumerable<Type> SupportedTypes
        {
            get
            {
                yield return typeof(Boy);
            }
        }
    }
    

    然后在web.config中注册这个Converter

    <add name="BoyConverter" type="BoyConverter,App_Code"/>
     

    这样我们打破了原本的循环引用,示例就可以正常通过啦

    改变客户端访问时的方法名

    • 客户端无法重载方法(可以通过判断arguments数量来模拟)
    • 如果服务器端出现了方法重载?

                    使用WebServiceAttribute指定客户端方法名

                    使用和真正的WebService相同的做法

                    [WebMethod(MessageName="…")]

    • 并非出现重载才能改变方法名称

            一个改变客户端访问时的方法名的示例

    首先创建一个名为MethodOverloadService.asmx的WebService

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    
    /// <summary>
    ///MethodOverloadService 的摘要说明
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    //若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。 
    [System.Web.Script.Services.ScriptService]
    public class MethodOverloadService : System.Web.Services.WebService 
    {
    
        [WebMethod]
        public int GetRandom()
        {
            return new Random(DateTime.Now.Millisecond).Next();
        }
    
        [WebMethod]
        public int GetRandom(int minValue, int maxValue)
        {
            return new Random(DateTime.Now.Millisecond).Next(minValue, maxValue);
        }
    }

         然后我们创建一个页面,引用这个WebService,并设置ScriptManager的InlineScript="true",这样生成的代理就直接写到页面上了,我们可以看到,页面中只注册下面的一个GetRandom方法,因为第一个方法已经被覆盖

          如果我们要避免这种客户端对同名方法的覆盖,我们就要改变客户端访问这个方法时的名字,只需要在任意一个这样的方法下面加上如下代码就可以实现了

    [WebMethod(MessageName = "GetRangeRandom")]

    这时我们就可以在页面中找到它注册了两个方法 ,方法名分别是GetRandom和GetRangeRandom,好了,成功啦

    使用HTTP GET访问WebService方法

    • 使用ScriptMethodAttribute进行标记(UseHttpGet属性设置为true),出于安全性考虑,默认只使用POST
    • 客户端使用代理的方法没有任何变化
    • 参数将使用Query String进行传递
    • 性能较HTTP POST方法略有提高
    • 一些特性略有改变(缓存的基础等,HTTP GET是没有缓存的)

    一个使用HTTP GET访问WebService方法的示例

    首先创建一个名为UserHttpGetService的WebService

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    using System.Web.Script.Services;
    
    /// <summary>
    ///UserHttpGetService 的摘要说明
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    //若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。 
    [System.Web.Script.Services.ScriptService]
    public class UseHttpGetService : System.Web.Services.WebService
    {
        [WebMethod]
        public int GetRandom()
        {
            return new Random(DateTime.Now.Millisecond).Next();
        }
    
        [WebMethod]
        [ScriptMethod(UseHttpGet = true)]
        public int GetRangeRandom(int minValue, int maxValue)
        {
            return new Random(DateTime.Now.Millisecond).Next(minValue, maxValue);
        }
    }

    然后创建页面,代码如下

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager ID="ScriptManager1" runat="server">
                <Services>
                    <asp:ServiceReference Path="~/Demo03/UseHttpGetService.asmx" InlineScript="true" />
                </Services>
            </asp:ScriptManager>
            
            <input type="button" value="Get Random" onclick="getRandom()" />
            <input type="button" value="Get Range Random" onclick="getRandom(50,100)" />
            
            <script language="javascript" type="text/javascript">
                function getRandom(minValue, maxValue) {
                    if (arguments.length != 2) {
                        UseHttpGetService.GetRandom(onSucceeded);
                    }
                    else {
                        UseHttpGetService.GetRangeRandom(minValue, maxValue, onSucceeded);
                    }
                }
    
                function onSucceeded(result) {
                    alert(result);
                }
            </script>
        </form>
    </body>
    </html>

    这样我们就完成了这个示例,我们会发现页面代码和以前访问WebService是一摸一样的,但是我们使用HttpWatch查看就可以发现,他们的访问方式是不一样的,而且我们打开页面源代码也可以发现以下代码

    this._invoke(this._get_path(), 'GetRandom',false,{},succeededCallback,failedCallback,userContext); 
    this._invoke(this._get_path(), 'GetRangeRandom',true,{minValue:minValue,maxValue:maxValue},succeededCallback,failedCallback,userContext); }}
    

    这里的false和true就表示是不是使用HTTP GET

    让WebService方法返回XML对象

    • 默认以JSON格式返回数据
    • 使用ScriptMethodAttribute进行标记(ResponseFormat属性设置为Xml,Response的Context-Type将为text/xml)
    • 可以使用字符串拼接出XML并输出
    • 可以返回Xml相关类型(XmlDocument,XmlElement)
    • 返回普通对象时将使用XmlSerializer输出
    一个让方法返回XML对象的示例

    首先创建一个Employee类

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    /// <summary>
    ///Employee 的摘要说明
    /// </summary>
    public class Employee
    {
        private string _firstname;
        private string _lastname;
        private string _title;
        
        public Employee(string firstname,string lastname,string title)
        {
            this._firstname = firstname;
            this._lastname = lastname;
            this._title = title;
        }
        public Employee() { }
        public string FirstName
        {   
            get { return this._firstname; }
            set { this._firstname = value; }
        }
        public string LastName
        {
            set { this._lastname = value; }
            get { return this._lastname; }
        }
        public string Title
        {
            get { return this._title; }
        }
    
        public int Salary { get; set; }
    
        public string FullName
        {
            get
            {
                return this.FirstName + this.LastName;
            }
        }
        public static implicit operator string(Employee employee)
        {
            return employee.FullName;
        }
    }
    

    然后创建一个ReturnXmlService.asmx

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    using System.Web.Script.Services;
    using System.Xml;
    
    /// <summary>
    ///ReturnXmlService 的摘要说明
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    //若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。 
    [System.Web.Script.Services.ScriptService]
    public class ReturnXmlService : System.Web.Services.WebService
    {
        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Xml)]
        public XmlNode GetXmlDocument()
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml("<Employee><Name>Xiaoyaojian</Name><Salary>5000</Salary></Employee>");
    
            return doc;
        }
    
        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Xml)]
        public XmlNode GetXmlElement()
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml("<Employee><Name>Xiaoyaojian</Name><Salary>5000</Salary></Employee>");
    
            return doc.DocumentElement;
        }
    
        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Xml)]
        public Employee GetEmployee()
        {
            return new Employee("bai", "yulong","developer");
        }
    
        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Xml)]
        public string GetXmlString()
        {
            return "<Employee><Name>Xiaoyaojian</Name><Salary>5000</Salary></Employee>";
        }
    
        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Xml, XmlSerializeString = true)]
        public string GetSerializedString()
        {
            return "<Employee><Name>Xiaoyaojian</Name><Salary>5000</Salary></Employee>";
        }
    }
    
    

    然后创建页面,使用这个WebService

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager ID="ScriptManager1" runat="server">
                <Services>
                    <asp:ServiceReference Path="~/Demo03/ReturnXmlService.asmx" InlineScript="true"/>
                </Services>
            </asp:ScriptManager>
            
            <input type="button" value="GetXmlDocument" onclick="ReturnXmlService.GetXmlDocument(onSucceeded);" /><br /><br />
            <input type="button" value="GetXmlElement" onclick="ReturnXmlService.GetXmlElement(onSucceeded);" /><br /><br />
            <input type="button" value="GetEmployee" onclick="ReturnXmlService.GetEmployee(onSucceeded);" /><br /><br />
            <input type="button" value="GetXmlString" onclick="ReturnXmlService.GetXmlString(onSucceeded);" /><br /><br />
            <input type="button" value="GetSerializedString" onclick="ReturnXmlService.GetSerializedString(onSucceeded);" />
            
            <script language="javascript" type="text/javascript">
                function onSucceeded(result)
                {
                    alert(result.xml);
                }
            </script>
        </form>
    </body>
    </html>
     

    我们比较弹出的效果,就可以看出不同的标记和不同的返回类型,客户端对次不同的处理啦

    在WebService方法中使用Session

    • ASP.NET中每个请求都由一个IHttpHandler对象来处理
    • 在处理时要使用Session则需要让Handler对象实现IRequiresSessionState借口
    • RestHandlerFactory根据所请求的方法的标记来选择是否启用Session
    • 启用方法:在WebMethodAttribute中标记(EnableSession属性设置为true)
    一个在WebService方法中使用Session的示例

    首先创建一个名为EnableSessionService.asmx的WebService

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    using System.Web.Script.Services;
    
    /// <summary>
    ///EnableSessionService 的摘要说明
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    //若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。 
    [System.Web.Script.Services.ScriptService]
    public class EnableSessionService : System.Web.Services.WebService
    {
        [WebMethod(EnableSession = true)]
        public int AddOne()
        {
            object objValue = Session["value"];
            int value = objValue == null ? 0 : (int)objValue;
            value++;
            Session["value"] = value;
            return value;
        }
    
        [WebMethod(true)]
        public int AddTwo()
        {
            object objValue = Session["value"];
            int value = objValue == null ? 0 : (int)objValue;
            value += 2;
            Session["value"] = value;
            return value;
        }
    }
    
    

    然后创建一个页面使用它

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager ID="ScriptManager1" runat="server">
                <Services>
                    <asp:ServiceReference Path="~/Demo03/EnableSessionService.asmx" InlineScript="true" />
                </Services>
            </asp:ScriptManager>
            
            <input type="button" value="Add One" onclick="addOne()" />
            <input type="button" value="Add Two" onclick="addTwo()" />
            
            <script language="javascript" type="text/javascript">
                function addOne() {
                    EnableSessionService.AddOne(onSucceeded);
                }
    
                function addTwo() {
                    EnableSessionService.AddTwo(onSucceeded);
                }
                
                function onSucceeded(result) {
                    alert(result);
                }
            </script>
        </form>
    </body>
    </html>

    这样我们就可以正确的使用WebService访问Session啦,并且我们发现[WebMethod(EnableSession = true)]和[WebMethod(true)]的作用是一样的,区别就是,当我们需要设置一写其他属性的时候,我们就只能使用[WebMethod(EnableSession = true)]这种方式啦

    安全性

    • 完全适用ASP.NET的认证机制(使用FormsAuthentication,Impersonation,PrincipalPermission)
    • ASP.NET AJAX访问WebService可以操作cookies
    一个关于安全性的示例

    首先,我们应该确定一下,web.config中的authentication标记的mode属性是否非Forms

    创建一个名为SecurityService.asmx的WebService

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    
    /// <summary>
    ///SecurityService 的摘要说明
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    //若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。 
    [System.Web.Script.Services.ScriptService]
    public class SecurityService : System.Web.Services.WebService
    {
        [WebMethod]
        public string HelloWorld()
        {
            if (!HttpContext.Current.User.Identity.IsAuthenticated)
            {
                throw new ApplicationException("Please Login First");
            }
            return "Hello " + HttpContext.Current.User.Identity.Name;
        }
    }
    
    

    然后创建一个页面使用它

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager ID="ScriptManager1" runat="server">
                <Services>
                    <asp:ServiceReference Path="~/Demo03/SecurityService.asmx" InlineScript="true" />
                </Services>
            </asp:ScriptManager>
            
            <input type="button" value="Call" onclick="call()" />
            
            <script language="javascript" type="text/javascript">
                function call() {
                    SecurityService.HelloWorld(onSucceeded,onFailed);
                }
    
                function onSucceeded(result) {
                    alert(result);
                }
    
                function onFailed(error) {
                    alert(error.get_message());
                }
            </script>
        </form>
    </body>
    </html>
    

    这时,我们点击页面中的Call按钮,就会弹出一个Please login first,我们成功了阻止了一次匿名的登陆

    我们在页面的Load事件中增加如下代码

    FormsAuthentication.SetAuthCookie("Xiaoyaojian",false); 

    这样,我们在页面加载的时候就为它登陆了,页面就会正常显示我们想要的内容:Hello ,Xiaoyaojian(注意要在页面代码中引入System.Web.Security命名空间)

    客户端代理的一些解释

    • 每个Service类对应客户端的一个代理类(还记得Type.registerNamespace这些东西吗?)
    • 每个代理类为Sys.Net.WebServiceProxy类的子类
    • 代理类的每个方法均对应一个类的静态方法(我们使用调用WebService的时候,可没有使用一个net来创建对象)
    • 最终由Sys.Net.WebServiceProxy.invoke方法发出请求

    invoke方法签名

                  Sys.Net.WebServiceProxy.invoke=function(

                               servicePath//Service路径

                                methodName//方法名

                                useGet//是否使用HTTP GET访问

                                params//参数

                                onSucceeded//成功后的回调函数

                                onFailded//失败后的回调函数

                                userContext//用户上下文对象

                                timtOut//超时时间

                           ){};

    一个示例

    创建一个页面,但是这回我们不同的是,不向ScriptManager中添加一个WebService的引用

    我们使用如下代码

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager ID="ScriptManager1" runat="server">
            </asp:ScriptManager>
            
            <input type="button" value="Get Range Random" onclick="getRandom(0,100)" />
            
            <script language="javascript" type="text/javascript">
                function getRandom(minValue, maxValue) {
                    Sys.Net.WebServiceProxy.invoke(
                        "UseHttpGetService.asmx",
                        "GetRangeRandom",
                        true,
                        {"minValue":minValue,"maxValue":maxValue},
                        onSucceeded,
                        null,
                        null,
                        -1
                    );
                    }
    
                    function onSucceeded(result) {
                        alert(result);
                    }
            </script>
        </form>
    </body>
    </html>
    

    这里同样我们访问到了UseHttpGetService这个WebService,这就是我们使用Invoke的一个方法

  • 相关阅读:
    QQ第三方登录(二)
    QQ第三方登录(一)
    Nginx防盗链
    TP-网页静态化
    TP5实现邮件发送(PHP 利用QQ邮箱发送邮件「PHPMailer」)
    docker安装elasticsearch和head插件
    git的安装方法
    ELK elasticsearch 因磁盘爆满导致无法 FORBIDDEN/12/index read-only / allow delete (api)
    vmware 系统网络发生变化后,本机安装的vmware无法通过客户端工具连接上的问题解决
    docker 容器视图工具portainer简单使用记录
  • 原文地址:https://www.cnblogs.com/xiaoyaojian/p/2214338.html
Copyright © 2020-2023  润新知