首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

16.4  控制数据在Web服务中如何传输

从Web服务调用返回数据时,数据会串行化为XML,这说明,只能返回基本类型,或者是能自行串行化的类型(如DataSet)。如果有一个强类型的业务层,而且希望把它作为一个Web方法的结果返回,首先要做的是确保这个类有一个无参数构造函数,否则它将无法串行化。

接下来,必须确保希望串行化的所有属性都是可读写的,因为只读属性在串行化过程中会被忽略(方法也是一样)。考虑代码清单16-8,这里显示了一个用于Web服务中的简单类。

代码清单16-8  Shipper类

public class Shipper

{

  private int _id;

  private string _companyName;

  private string _phone;

  public Shipper()

  {

  }

  public Shipper(int id, string companyName, string phone)

  {

    _id = id;

    _companyName = companyName;

    _phone = phone;

  }

  public int ID

  {

    get { return _id; }

    set { _id = value; }

  }

  public string CompanyName

  {

    get { return _companyName; }

    set { _companyName = value; }

  }

  public string Phone

  {

    get { return _phone; }

    set { _phone = value; }

  }

}

当Web服务返回这个类的一个实例时,XML中对应各属性分别包含一个元素,如代码清单16-9所示。

代码清单16-9  串行化的Shipper类

<?xml version="1.0" encoding="utf-8"?>

<Shipper xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  xmlns:xsd="http://www.w3.org/2001/XMLSchema"

  xmlns="http://aspnetillustrated.org/services/">

  <ID>5</ID>

  <CompanyName>Tortoise Inc</CompanyName>

  <Phone>555 123 1234</Phone>

</Shipper>

16.4.1  定制串行化

通过对类和属性指定性质,可以改变生成XML的方式。例如,考虑代码清单16-10。这个类有一个XmlRoot性质,它定义了根元素的名。ID属性有XmlAttribute性质,这指定了AttributeName,使得ID属性成为父元素上的一个XML属性。Phone属性有XmlElement性质,指定了ElementName,并指定它可以包含null值。

代码清单16-10  对Shipper类增加性质完成串行化

[XmlRoot("RegionalShipper")]

public class Shipper

{

  private int _id;

  private string _companyName;

  private string _phone;

  public Shipper()

  {

  }

  public Shipper(int id, string companyName, string phone)

  {

    _id = id;

    _companyName = companyName;

    _phone = phone;

  }

  [XmlAttribute(AttributeName = "ShipperID")]

  public int ID

  {

    get { return _id; }

    set { _id = value; }

  }

  public string CompanyName

  {

    get { return _companyName; }

    set { _companyName = value; }

  }

  [XmlElement(ElementName = "PhoneNumber",

    IsNullable = true)]

  public string Phone

  {

    get { return _phone; }

    set { _phone = value; }

  }

}

从Web服务返回Shipper类时,会考虑这些定制性质,从而得到代码清单16-11中所示的XML。

代码清单16-11  定制的串行化Shipper类

<?xml version="1.0" encoding="utf-8"?>

<RegionalShipper

  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  xmlns:xsd="http://www.w3.org/2001/XMLSchema"

  ShipperID="5"

  xmlns="http://aspnetillustrated.org/services/">

  <CompanyName>Tortoise Inc</CompanyName>

  <PhoneNumber>555 123 1234</PhoneNumber>

</RegionalShipper>

16.4.2  串行化集合

集合会串行化为结构化XML,其父元素的默认名为ArrayOfClass,这里Class是串行化的类的类名。例如,代码清单16-12 显示了一个Web服务的结果,它返回Shipper对象的一个泛型列表(List<Shipper>)。

代码清单16-12  串行化的集合

<?xml version="1.0" encoding="utf-8"?>

<ArrayOfShipper xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  xmlns:xsd="http://www.w3.org/2001/XMLSchema"

  xmlns="http://aspnetillustrated.org/services/">

  <Shipper ShipperID="1">

    <CompanyName>Speedy Express</CompanyName>

    <PhoneNumber>(503) 555-9831</PhoneNumber>

  </Shipper>

  <Shipper ShipperID="2">

    <CompanyName>United Package</CompanyName>

    <PhoneNumber>(503) 555-3199</PhoneNumber>

  </Shipper>

  <Shipper ShipperID="3">

    <CompanyName>Federal Shipping</CompanyName>

    <PhoneNumber>(503) 555-9931</PhoneNumber>

  </Shipper>

</ArrayOfShipper>

可以通过向Web方法增加一个额外的性质来控制顶层元素。例如,如代码清单16-13所示,可以指定所返回元素的名。

代码清单16-13  指定返回元素名

[WebMethod]

[return: XmlElement("Shippers")]

public List<Shipper> GetShippers()

顶级元素不再是ArrayOfShipper,而是Shippers。注意,看上去这只会影响SOAP请求,而不影响HTTP POST请求,Web服务帮助页面使用的是后者。可以检查WSDL或帮助页面的示例输出来加以区别。

还可以使用XmlElement性质从生成的XML去除一个间接层。例如,考虑代码清单16-14中的类,这是Shipper对象的一个集合。

代码清单16-14  ShipperCollection类

public class ShipperCollection

{

  private List<Shipper> _items;

  public ShipperCollection()

  {

    _items = new List<Shipper>();

  }

  public List<Shipper> Items

  {

    get { return _items; }

    set { _items = value; }

  }

}

代码清单16-15显示了从一个Web方法返回ShipperCollection类的结果,可以看到, 这里有一个多余的Items元素。

代码清单16-15  串行化的ShipperCollection类

<?xml version="1.0" encoding="utf-8"?>

<ShipperCollection

  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  xmlns:xsd="http://www.w3.org/2001/XMLSchema"

  xmlns="http://aspnetillustrated.org/services/">

  <Items>

    <Shipper ShipperID="1">

      <CompanyName>Speedy Express</CompanyName>

      <PhoneNumber>(503) 555-9831</PhoneNumber>

    </Shipper>

    <Shipper ShipperID="2">

      <CompanyName>United Package</CompanyName>

      <PhoneNumber>(503) 555-3199</PhoneNumber>

    </Shipper>

    <Shipper ShipperID="3">

      <CompanyName>Federal Shipping</CompanyName>

      <PhoneNumber>(503) 555-9931</PhoneNumber>

    </Shipper>

    <Shipper ShipperID="14">

      <CompanyName>Tortoise Couriers</CompanyName>

      <PhoneNumber>12555 123 456</PhoneNumber>

    </Shipper>

    <Shipper ShipperID="15">

      <CompanyName>Tortopoise Inc</CompanyName>

      <PhoneNumber>555 123 1234</PhoneNumber>

    </Shipper>

  </Items>

</ShipperCollection>

ShipperCollection是根元素,其Items属性有一个元素,每个Shipper又各有自己的一个元素。要删除多余的Items元素,可以在集合中Items属性上使用XmlElement性质(如代码清单16-16所示),其结果是Shipper元素将成为ShipperCollection的子元素。

代码清单16-16  对集合加性质

[XmlElement(ElementName = "Shipper")]

public List<Shipper> Items

还可以用很多其他性质来控制类中的集合和数组,如使用XmlArray和XmlArrayItem来指示如何串行化数组和数组元素。

16.4.3  手动地串行化

默认情况下,ASP.NET会为你完成串行化和模式创建,不过如果必要,你也可以自行完成,为此要实现IXmlSerializable接口。例如,考虑代码清单16-17,它就实现了这个接口。不同于ASP.NET 1.x,这里没有使用GetSchema方法来定义模式,而是在类上用XmlSchemaProvider性质来指定提供模式的方法。ReadXml和WriteXml方法将完成具体的串行化。

代码清单16-17  手动串行化类

[XmlSchemaProvider("CustomShipperSchema")]

public class CustomShipper : IXmlSerializable

{

  // standard properties and methods

  public static XmlQualifiedName

    CustomShipperSchema(XmlSchemaSet set)

  {

    XmlSchema s = new XmlSchema();

    s.Id = "Test";

    s.TargetNamespace = "urn:types-nw-com";

    XmlSchemaComplexType t = new XmlSchemaComplexType();

    t.Name = "CustomShipper";

    XmlSchemaElement shipper = new XmlSchemaElement();

    shipper.Name = "shipper";

    XmlSchemaElement id = new XmlSchemaElement();

    id.Name = "id";

    id.Parent = shipper;

    XmlSchemaElement name = new XmlSchemaElement();

    name.Name = "shipperName";

    name.Parent = shipper;

    XmlSchemaElement phone = new XmlSchemaElement();

    phone.Name = "phone";

    phone.Parent = shipper;

    XmlQualifiedName n = new

      XmlQualifiedName(t.Name, s.TargetNamespace);

    shipper.SchemaTypeName = n;

    s.Items.Add(t);

    s.Items.Add(shipper);

    set.Add(s);

    return n;

  }

  // this is not used in v 2.0 of the framework

  // instead the method defined by the attribute sets the schema

  public XmlSchema GetSchema()

  {

      return null;

  }

  public void ReadXml(XmlReader reader)

  {

    XmlNodeType type = reader.MoveToContent();

  if (type == XmlNodeType.Element &&

    reader.LocalName == "shipper")

  {

    reader.ReadToDescendant("id");

    _id = int.Parse(reader.Value);

    reader.ReadToNextSibling("shipperName");

    _companyName = reader.Value;

    reader.ReadToNextSibling("phone");

    _phone = reader.Value;

  }

}

public void WriteXml(XmlWriter writer)

{

  writer.WriteStartElement("shipper", "urn:nw-com");

  writer.WriteElementString("id", _id.ToString());

  writer.WriteElementString("shipperName", _companyName);

  writer.WriteElementString("phone", _phone);

  writer.WriteEndElement();

}

利用这个技术,就能充分控制所生成的模式,还能控制对什么串行化,这对于需要互操作性的情况很有用。

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论