处理 xml 数据类型和 CLR 用户定义类型

后续版本的 Microsoft SQL Server 将删除该功能。 请避免在新的开发工作中使用该功能,并着手修改当前还在使用该功能的应用程序。

自 SQL Server 2005 起,在本机 XML Web 服务中,传递某些类型(如 xml 数据类型或公共语言运行时 (CLR) 用户定义类型)需要执行一些其他开发任务。本主题介绍为了使基于 XML Web 服务的应用程序能够在 Web 方法和参数化查询中使用 xml 和 CLR 用户定义类型而必须执行的任务。

注意注意

本主题假定您已具有在 SQL Server 中部署本机 XML Web 服务的基础知识,包括熟悉某些任务,例如创建端点、借助 Web 方法来利用 SQL 可编程性,以及编写适用于使用其他内置 SQL 类型的 SQL Server 的基本 Web 客户端应用程序。如果要查看此信息,请参阅 本机 XML Web 服务概念部署本机 XML Web 服务使用本机 XML Web 服务的最佳方法

在 Web 客户端应用程序中处理 xml 数据类型

要使 Web 客户端应用程序正确处理 xml 数据类型,其详细过程取决于应用下列哪一个方案:

  • 使用作为端点的 Web 方法显示的存储过程。

  • 使用端点的 SQL 批处理 (sqlbatch) 功能来执行参数化查询。

这两个方案都需要使用和填充 myEndpoint**::xml** 结构来处理 xml 数据类型的参数化实例。在此结构中,myEndpoint 表示在通过客户端代码传递 xml 数据类型的实例时所使用端点的真实名称。此结构在端点 Web 代理类中声明。

在添加或更新对 Visual Studio 项目中显示 Web 方法的端点的 Web 引用时,将创建 myEndpoint**::xml** 结构。但是,您必须基于在客户端应用程序代码中使用的是类型化的 XML 还是非类型化的 XML,相应地在自定义 Web 代理类中填充初始生成的 myEndpoint**::xml** 结构。

对于 Web 方法中的非类型化 xml 数据类型参数实例,myEndpoint**::xml** 结构在代理类中将它们显示为 System.Xml.XmlNode 类型的一个数组。因此,若要传入 xml 数据类型参数实例,请手动构造并填充 XML 节点的数组,或者最好使用 System.Xml.XmlDocumentFragment 来进行操作。有关详细信息,请参阅在 Visual Studio 客户端应用程序中使用 xml 数据类型

对于 Web 方法中的类型化 xml,将在 Web 代理类中生成自定义类型并根据下列格式命名:方法名称加上单词 Type,后接参数名称。例如,如果通过名称 GetXmlInfo 来显示 Web 方法,并且采用名称为 T 的 xml 数据类型参数来传递作为输入的类型化的 XML,则在 Web 代理类中显示的自定义类型的名称将是 GetXmlInfoTypeT。因为此自定义类型是从 myEndpoint**::xml** 结构继承的,因此它类似于将类型化的 XML 作为一个 System.Xml.XmlNode 数组显示。

在参数化查询中处理 xml 数据类型与在 Web 方法中处理 xml 数据类型相似,但有一点不同:必须通过非类型化的 XML 使用的类型 (myEndpoint**::xml**) 从客户端传递类型化的 XML。

准备好 myEndpoint**::xml** 结构后,便可以将 xml 数据类型实例作为已定义结构中的一个 System.Xml.XmlNode 数组来显示,而该结构又可以包含在 SqlParameter.Value 对象中。

参数化查询要求具有 SQL 批处理功能。这可能涉及下面的其他准备工作:

  • 端点必须启用 SQL。这意味着创建或修改端点时,使用了 BATCHES=ENABLED。

  • 在 Web 代理类中,为启用批处理的端点添加或更新 Web 引用时,将包含 sqlbatch() 方法。

对于类型化的 XML 参数,将更新 Web 代理类中的 sqlbatch() 方法,以包含与注册 System.Data.SqlClient.SqlParameter 对象的 XML 架构集合有关的任何其他属性(XmlSchemaCollectionDatabase、XmlSchemaCollectionName、XmlSchemaCollectionOwningSchema)的设置。

注意注意

对于显示 xml 数据类型的 Web 方法和参数化查询,在输出中将返回 System.Data.DataSet(作为对象数组的一部分)并将其内容放置在 DataGrid 中以在客户端应用程序中将结果可视化,DataSet 不使用 Web 代理类型 (myEndpoint::xml),而使用 CLR System.Data.SqlTypes.SqlXml 类型。

在 Web 客户端应用程序中处理 CLR 用户定义类型

若要在 Web 客户端应用程序中处理 CLR 用户定义类型,必须完成下列步骤:

  1. 编写 CLR 用户定义类型,并在 DLL(如 MyType.dll)中对其进行编译。

    在 Visual Studio 2005 中,编写 CLR 用户定义类型(类或结构)并将其编译为一个程序集。该类型程序集必须符合 SQL Server 对实现用户定义类型方面的要求,从而能够在 SQL Server 实例上安装和注册程序集。有关详细信息,请参阅 CLR 用户定义类型中的“UDT 实现方面的要求”。

  2. 若要生成 XML 序列化程序附带 DLL,如果您尚未实现 IXMLSerializable,则可以对类型程序集 DLL 运行 Sgen.exe。生成的 DLL 将具有与 MyType.XmlSerializers.dll 类似的名称。

    除了满足 SQL Server 对 CLR 用户定义类型方面的基本要求外,CLR 用户定义类型还必须是 XML 可序列化的,才能在 SQL Server 中使用本机 XML Web 服务。有关详细信息,请参阅 CLR 用户定义类型中的“XML 序列化”。

  3. 使用 CREATE ASSEMBLY 在 SQL Server 实例上安装类型程序集 DLL。

    如果尚未实现 IXMLSerializable 但完成了步骤 2,则仍必须使用 CREATE ASSEMBLY 在 SQL Server 实例上安装 XML 序列化程序附带 DLL。

  4. 将 CLR 用户定义类型序列化为 XML 并将其包含在上一部分介绍的 myEndpoint**::xml** 类似结构中。

    在服务器上安装 CLR 用户定义类型后,若要从本机 XML Web 服务客户端应用程序将此 CLR 用户定义类型的实例传递到 SQL Server,首先必须将 CLR 用户定义类型序列化为 XML 格式并将其包含在 XML结构中。

    下列代码显示了如何将 CLR 用户定义类型序列化为 XML 格式并将其放入 XML 元素 (System.Xml.XmlElement)。

    // Create the user-defined type class on the client.
    SqlString s = new SqlString("0:0");
    UdtClientApp.Point pnt = Point.Parse(s);
    // Invoke the method and pass in a user-defined type.You will need
    // to convert this to XmlElement before you can pass it to SQL Server.
    System.IO.MemoryStream writer = new System.IO.MemoryStream();
    System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(UdtClientApp.Point));
    serializer.Serialize(writer, pnt);
    writer.Seek(0, System.IO.SeekOrigin.Begin);
    System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
    xmlDoc.Load(writer);
    System.Xml.XmlElement udtXml = xmlDoc.DocumentElement;
    
  5. 根据 CLR 用户定义类型是否出现在客户端,您可能还必须将输出参数从其 CLR 用户定义类型 XML 格式反序列化回其用户定义类型格式。

    下列代码显示了如何在客户端代码中将用户定义类型 XML 反序列化回 CLR 用户定义类型。在此示例中,CLR 用户定义类型为 Point。

    Object[] results = proxy.GetPointUdt(Convert.ToInt16(textBox1.Text), ref udtXml);
    //Deserialze the XML into user-defined type.
    TextReader reader = new StringReader(udtXml.OuterXml);
    // pnt was already defined as UdtClientApp.Point pnt = Point.Parse(s);
    pnt = (UdtClientApp.Point) serializer.Deserialize(reader);
    

    请注意,如果在客户端将 CLR 用户定义类型作为非类型化的 XML 使用,则将不必执行此反序列化过程。

也可以将 CLR 用户定义类型作为参数按照与 xml 数据类型类似的方法传递到参数化查询。必须使用 myEndpoint**::xml** 类型从客户端传递 XML 序列化格式的 CLR 用户定义类型。

对于涉及 CLR 用户定义类型的参数化查询,将在 System.Data.SqlClient.SqlParameter 结构上设置不同的值。例如,下列属性设置用于 CLR 用户定义类型:

  • 必须将 SqlDbType 属性设置为一个 Udt 值。

  • 对于 ClrTypeName 属性,必须按照所安装的用户定义类型在 SQL Server 实例上的注册,将其设置为该用户定义类型的 SQL Server 三部分限定名 (MyDatabase**.MySchema.**MyUdtType)。