Asp.net Ajax 学习笔记7 客户端访问WebService(中)

本文介绍如何在客户端和服务端之间正确地传递复杂对象,包括构造、序列化和反序列化的最佳实践,以及如何处理循环引用等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、使用复杂参数或返回值

  • 作为参数的类型一定要有默认的构造函数,就是说要有无参的构造函数。
  • 客户端使用的类型必须要和服务端的类型共有域变量及属性,注:设置的属性必须要有Setter方法。客户端使用服务端的复杂类型有两种方式构造一个对象。1是使用JSon字符串的形势,设置一个变量,让它的值类似与{"名称1":值1, "名称2":值2}这种方式,名称1,名称2,要与服务段公有的字段相同。
    var color = {"Red" : 50"Green" : 100"Blue" : 200};
    Red、Green、Blue都与服务段的Color对象的字段名字相同。2是实例化一个对象,对象名为[Namespaces].ClassName(),然后是用如下代码,给对象的字段赋值
    var color = new ComplexType.Color();
    color.Red 
    = 50;
    color.Green 
    = 100;
    color.Blue 
    = 200;
    这叫复杂对象的代理。实例化时只能使用类的无参构造函数。
  • 在客户端和服务段传递对象时自动进行(JSon)序列化与反序列化。
  • 生成复杂对象代理时,需要在服务端使用GenerateScriptType属性标记要代理的类[GenerateScriptType(typeof(Color))]注:此标记可以标记在类、接口以及方法上
  • 如果服务器端类型有基类、派生类等继承关系,当然可以根据具体的情况生成具体的派生类对象,还可以直接实例化一个Object对象,设置这个对象__type属性,在把这个对象传递到服务端时,服务端可根据此标记自动反序列化为一个派生类,这样可以实现一个多态的效果,这个Object对象就是基类的对象,根据__type属性自动实例化一个派生类

2、使用JavaScriptConverter

JavaScriptConverter可以用来处理存在循环引用的类和结果不是开发人员所期望那样的类型,如一个类型没有无参的构造函数,那么是否就不能在客户端使用了?使用JavaScriptConverter就能够在客户端使用
使用DataTable这样的复杂类型时,可以使用JavaScriptConverter来解决

<system.web.extensions>
  
<scripting>
   
<webServices>
    
<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>

这是使用别人已经写好的JavaScriptConverter来使用DataSet,DataRow,DataTable数据类型。

3、自己编写JavaScriptConverter

自定义JavaScriptConverter需要继承JavaScriptConverter对象,并重写Deserialize、Serialize、SupportedTypes方法和属性

namespace Converter
{

 
public class BoyConverter : JavaScriptConverter
 
{
        
//此方法在由客户端的对象向服务段对象进行传递时调用
  public override object Deserialize(IDictionary<stringobject> dictionary, Type type, JavaScriptSerializer serializer)
  
{
            
//实例化一个Boy对象
   Boy boy = new Boy();
            
//将Boy的Name被设置为dictionary的Name的key的值
   boy.Name = (string)dictionary["Name"];
            
//注意dictionary["GirlFriend"]的值是一个JSon对象,用来保存客户端GirlFriend的对象
            
//所以需要用JavaScriptSerializer来将此JSon对象转换为一个服务段Gril对象
   boy.GirlFriend = serializer.ConvertToType<Girl>(dictionary["GirlFriend"]);
            
//设置boy的GirlFriend的BoyFirend,在服务端不用担心循环引用的问题
   boy.GirlFriend.BoyFriend = boy;

            
//返回被设置好的Boy对象
   return boy;
  }


        
//此方法在由服务端对象向客户端对象进行传递是调用
  public override IDictionary<stringobject> Serialize(object obj, JavaScriptSerializer serializer)
  
{
            
//转换传递进来的参数为Boy类型
   Boy boy = (Boy)obj;
            
//实例化一个字典类型
   IDictionary<stringobject> result = new Dictionary<stringobject>();

            
//设置字典类型的key为Name,值为Boy的Name
   result["Name"= boy.Name;

            
//将boy的GirFriend的BoyFriend引用设置为空,避免在客户端出现循环引用的问题
   boy.GirlFriend.BoyFriend = null;
            
//设置字典类型的key为GirlFriend为Boy的GirlFriend
   result["GirlFriend"= boy.GirlFriend;
            
//返回IDictionary对象,到客户端被转换为JSon对象,并且,不能使用boy.GirlFriend.BoyFriend
            
//类似的代码
   return result;
  }


  
public override IEnumerable<Type> SupportedTypes
  
{
   
get
   
{
                
//在 foreach 每次循环调用迭代程序的 
                
//MoveNext 方法时,它都从前一次 yield return 语句停止的地方开始执行
    yield return typeof(Boy);
   }

  }

 }
在实现好JavaScriptConverter类之后,需要在WebConfig里加上指定的Converter标签<add name="BoyConverter" type="Converter.BoyConverter, App_Code"/>加载的地方与DataTable类似。Name:转换者的名字,随便起 Type:Converter.BoyConverter转换者的命名空间加类名,App_Code:转换者类文件存放的地址,好像无所谓,我随便填也没出错

 

4、序列化和反序列化

  • 客户端的反序列化:
    Sys.Serialization.JavaScriptSerializer.deserialize('<%= this.SerializedDateTime %>');
  • 服务端的序列化
    JavaScriptSerializer serializer = new JavaScriptSerializer();
    serializer.Serialize(DateTime.Now);
    注意:客户端是静态方法。DateTime序列化后不是一个JSon字符串。
  • 上面是简单类型的序列化和反序列化,如果是复杂的对象类型需要用到JavaScriptTypeResolver
    自定义一个Resolver类并继承JavaScriptTypeResolver类,重写ResolveType、ResolveTypeId两个方法
    JavaScriptTypeResolver不是一个直接使用的类,他是用来辅助JavaScriptSerializer类的,作为构造函数的参数传入。
    namespace TypeResolver
    {
     
    /// <summary>
     
    /// Summary description for CustomizeTypeResolver
     
    /// </summary>

     public class CustomizeTypeResolver : JavaScriptTypeResolver
     
    {
            
    //从字符串标识获取一个Type对象
      public override Type ResolveType(string id)
      
    {
                
    //id就是从客户端对象的__type的值
       switch (id)
       
    {
        
    case "0"return typeof(Intern);
        
    case "1"return typeof(Vendor);
        
    case "2"return typeof(FulltimeEmployee);
       }

       
    return null;
      }

            
    //得到Type对象的标识字符串
      public override string ResolveTypeId(Type type)
      
    {
       
    if (type == typeof(Intern))
       
    {
                    
    //返回客户端就是__type属性的值
        return "0";
       }

       
    else if (type == typeof(Vendor))
       
    {
        
    return "1";
       }

       
    else if (type == typeof(FulltimeEmployee))
       
    {
        
    return "2";
       }

       
    return null;
      }

     }

    }
    这是类的定义
    Employee emp = null;
    switch (id)
    {
       
    case 0: emp = new Intern(); break;
       
    case 1: emp = new Vendor(); break;
       
    default: emp = new FulltimeEmployee(); break;
    }

    //用Resolver对象来实例一个JavaScriptSerializer对西那个
     JavaScriptSerializer serializer = new JavaScriptSerializer(new CustomizeTypeResolver());
    //序列化复杂对象
    return serializer.Serialize(emp);
    这是使用方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值