科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道应用软件实验讨论Atlas调用WebService时的复杂类型传递

实验讨论Atlas调用WebService时的复杂类型传递

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

客户端Javascript的松散,与服务端C#的严谨构成了一对矛盾,后台编写者必须为更加严谨地为前台提供松散的服务,否则客户端的胡乱使用会给网络和服务器造成不必要的负担。

作者:builder.com.cn 来源:来源网站 2007年11月25日

关键字: WebService Atlas

  • 评论
  • 分享微博
  • 分享邮件

在本页阅读全文(共19页)

近日拜读陈黎夫先生所著并发布在网上的《ASP.NET AJAX程序设计 第II卷:客户端Microsoft AJAX Library相关》的第三章《异步调用Web Service和页面中的类方法》(请参见陈先生博客http://www.cnblogs.com/dflying/archive/2007/06/12/780052.html),自己做了些实验以了解类型传递的原理,颇有些收获,现陈述如下,希望对ASP.NET AJAX的初学者有所帮助,并希望大家就其中不足多多给予指正。


实验1.服务端向客户端的传输

Step1.模仿陈先生在书中所举范例,可编写如下一个WebService类:

using System;
using System.Web;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Web.Script.Services;

public class Employee
{
    
private int m_id;
    
public int Id
    
{
        
get return m_id; }
        
set { m_id = value; }
    }


    
public string m_name;
    
public string Name
    
{
        
get return "My name is " + m_name + "!"; }
        
set { m_name = value; }
    }


    
private string m_email;
    
public string Email
    
{
        
get return m_email; }
        
set { m_email = value; }
    }


    
public int m_salary;
    [System.Web.Script.Serialization.ScriptIgnore]
    
public int Salary
    
{
        
get return m_salary; }
        
set { m_salary = value; }
    }


    
public Employee()
    
{
        ;
    }


    
public Employee(int id, string name, string email, int salary)
    
{
        m_id 
= id;
        m_name 
= name;
        m_email 
= email;
        m_salary 
= salary;
    }

}


[ScriptService]
[WebService(Namespace 
= "Delete.Ra")]
[WebServiceBinding(ConformsTo 
= WsiProfiles.BasicProfile1_1)]
[GenerateScriptType(
typeof(Employee))]
public class WebService : System.Web.Services.WebService {

    
public WebService () {

        
//如果使用设计的组件,请取消注释以下行 
        
//InitializeComponent(); 
    }


    [WebMethod]
    
public Employee CreateNewEmployee()
    
{
        
//返回一个已声明了GenerateScriptType的类
        return new Employee(0string.Empty, string.Empty, 0);
    }

    [WebMethod]
    
public bool SaveEmployee(Employee em)
    
{
        
// 保存到数据库中...
        return true;
    }

}

注意:其中与原文程序在访问权限上有微妙的不同。

Step2.在网页中调用CreateNewEmployee()方法

WebService.CreateNewEmployee(onSucceeded);

Step3.在程序中设置断点,并单步调试之。

稍加整理,可以得到如下的流程图(图中断点的符号表示被运行的语句或语句段):

SOAP中可以看出,
传给客户端的信息中只有
<名,值>的有序偶,而并没有将涉及对象内部的关联。
那么是不是在页面加载的一开始,类的内部关系就已经拷贝到客户端了呢?


实验2.类在客户端的样子

Step1.在客户端加入回调函数,获得新生成的类,并修改其值。

function Button4_onclick() {
    WebService.CreateNewEmployee(onSucceeded);
}

function onSucceeded(result) {
    
debugger;
    result.Name
="Delete";
    result.Email 
= "Delete.Ra@gmail.com";
    result.m_name
="Ra";
    
debugger;
}

注意:m_name应该是Name的内涵,在本程序中同时修改了这两个东西会发生什么事呢?加入断点进行调试。
属性被修改前:

属性被修改后:

可以看出,在客户端m_name和Name并无联系,Name属性对于客户端来说与m_name是对等的,都是简单的<名,值>关系。至于本程序中矛盾地对二者进行赋值到了服务端会怎么样请见实验3.2。

结论:
1.服务端的类在客户端并无内在联系。
2.能够表示成简单的<名,值>关系的数据才能被传递。

所以类的方法为什么不能传递就很好解释了。


实验3.1.从客户端向服务端传递(客户端篇)

Step1.在客户端加入代码:

function pageLoad() {
    
var e = new Employee();
    
debugger;
    e.Name 
= "Wo";
    e.Email
="Wp@abc.com";
    e.SpecialMember 
= 123;
    WebService.SaveEmployee(e);
}

值得注意的是,SpecialMember成员并没有在类的定义中出现,这样能行吗?运行一下试试。
运行到debugger语句:

(对象里什么都没有……)

赋值完毕:

(对象里面什么都有了,包括不该有的也有了……没办法,这是JavaScript的特性嘛~)

那么,这一数据能否顺利调用服务端的存储方法呢?测试一下webService的SaveEmployee方法就知道了:

POST /AJAXFuturesEnabledWebSite4/WebService.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "Delete.Ra/SaveEmployee"

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  
<soap:Body>
    
<SaveEmployee xmlns="Delete.Ra">
      
<em>
        
<m_name>string</m_name>
        
<m_salary>int</m_salary>
        
<Id>int</Id>
        
<Name>string</Name>
        
<Email>string</Email>
        
<Salary>int</Salary>
      
</em>
    
</SaveEmployee>
  
</soap:Body>
</soap:Envelope>

上传的数据中压根就没有其它人什么事,所以不用担心SpecialMember这种异类会入侵到老家去。
但是万一要是客户端的程序把正确的属性名打错了一个字字母,那就废了,值又传不过去(SOAP所限),又不报错(Javascript所限),死活查不出问题。


实验3.2.从客户端向服务端传递(服务端篇)
继续跟踪服务端存储过程,可以得到如下流程图:

 

 还记得我们在实验2中做了一个奇怪的赋值吗?将作为内核的m_name先赋值,再给其外延Name属性赋不同的值,这样做在上传的SOAP中肯定没有问题,那里有它们两个的位置,但在服务端存储过程中它们这对水火不容的冤家会怎样呢?

刚刚调用完类的默认构造函数之后:

可以看到,在刚刚构建好一个空的对象之后,第一个属性的setter被调用前,m_name就已经有值了,该值是我们在客户端程序中直接给m_name赋的值。说明在这之间有一步(即图中步骤2),传递了同名成员变量的值。

调用完Name的setter之后:

属性值覆盖了成员变量的赋值。因此,我们知道在客户端的这种矛盾的赋值并不会引起什么大的异常,只是我们白赋了一个值,白传了一个参数,白白浪费了一点点带宽。

结论:如果WebService的类设计不当,让使用者既能操作成员变量又能操作包装该成员变量的属性,则很可能引起逻辑上的错误。


实验3.3.传递错误的对象

Step1.在服务端随便再建一个类
Step2.在客户端获取该服务器类,创建对象并进行赋值等操作
Step3.调用上述的SaveEmployee()方法,并以这个新建的“外星人”对象作为参数
Step4.跟踪运行过程


结果:程序运行到图中第5步,即调用WebService方法时,抛出类型异常,程序中止。
结论:白传了一组数据,服务端白跑了4步程序。


额外的结论:
客户端Javascript的松散,与服务端C#的严谨构成了一对矛盾,后台编写者必须为更加严谨地为前台提供松散的服务,否则客户端的胡乱使用会给网络和服务器造成不必要的负担。

一点问题:
不是说要传递复杂的类型就要加上[GenerateScriptType(typeof(Employee))]声明吗?为什么把该声明注释掉之后程序依然照常运行呢?



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1901439

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章