如何使用 svcutil 从使用限制隐藏元素的 Web 服务生成 C# WCF 代理?
Posted
技术标签:
【中文标题】如何使用 svcutil 从使用限制隐藏元素的 Web 服务生成 C# WCF 代理?【英文标题】:Howto use svcutil to generate a C# WCF proxy from a web service that uses restriction to hide elements? 【发布时间】:2011-12-13 06:09:24 【问题描述】:我正在为一个或多或少不受我控制的 Web 服务创建客户端。这是架构的简化示例:
<xs:complexType name="A">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="element1" type="xs:string" />
<xs:element minOccurs="0" maxOccurs="1" name="element2" type="xs:string" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="B">
<xs:complexContent>
<xs:restriction base="A">
<xs:sequence>
<xs:element minOccurs="1" maxOccurs="1" name="element2" type="xs:string" />
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
简而言之,我们有一个包含所有元素的对象 A。该服务有几种基于 A 的类型,但有一些限制,因此继承的类型通常小于基本类型 - 这里以类型 B 为例。
在 Visual Studio 2010、SoapUI 等架构查看器中,这看起来符合预期。 A 有 2 个元素,B 只有 1 个(= 元素 2)。
通过使用 svcutil,我在类型 A 和 B 中都获得了完整的元素集,或者在使用选项时,我收到错误消息,例如:
错误:命名空间“http://tempuri.org/XMLSchema.xsd”中的类型“B”无法导入。通过限制派生的复杂类型 不支持。要么更改架构,以便类型可以映射到数据协定类型,要么使用 ImportXmlType 或使用 不同的序列化程序。
在继承类型中隐藏字段/属性不是我喜欢的实践/道路,但如果我无法让提供者更改 WSDL,我似乎必须这样做。
是否有 svcutil 的替代品可以正确处理此问题,还是我必须手动编写代理代码?
更新 1
正如 John Saunders 所指出的,我没有展示 svcutil 建议的结果。这部分是为了保持帖子简短......但这里是:
svcutil schema.xsd /importXmlTypes /datacontractonly 结果:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="A", Namespace="http://tempuri.org/XMLSchema.xsd")]
public partial class A : object, System.Runtime.Serialization.IExtensibleDataObject
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
private string element1Field;
private string element2Field;
public System.Runtime.Serialization.ExtensionDataObject ExtensionData
get
return this.extensionDataField;
set
this.extensionDataField = value;
[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
public string element1
get
return this.element1Field;
set
this.element1Field = value;
[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
public string element2
get
return this.element2Field;
set
this.element2Field = value;
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Xml.Serialization.XmlSchemaProviderAttribute("ExportSchema")]
[System.Xml.Serialization.XmlRootAttribute(IsNullable=false)]
public partial class B : object, System.Xml.Serialization.IXmlSerializable
private System.Xml.XmlNode[] nodesField;
private static System.Xml.XmlQualifiedName typeName = new System.Xml.XmlQualifiedName("B", "http://tempuri.org/XMLSchema.xsd");
public System.Xml.XmlNode[] Nodes
get
return this.nodesField;
set
this.nodesField = value;
public void ReadXml(System.Xml.XmlReader reader)
this.nodesField = System.Runtime.Serialization.XmlSerializableServices.ReadNodes(reader);
public void WriteXml(System.Xml.XmlWriter writer)
System.Runtime.Serialization.XmlSerializableServices.WriteNodes(writer, this.Nodes);
public System.Xml.Schema.XmlSchema GetSchema()
return null;
public static System.Xml.XmlQualifiedName ExportSchema(System.Xml.Schema.XmlSchemaSet schemas)
System.Runtime.Serialization.XmlSerializableServices.AddDefaultSchema(schemas, typeName);
return typeName;
在 Xml 级别上工作是不可取的,并且会迫使我们编写一个包装器。从 getgo 手动编码代理更容易。
svcutil schema.xsd /serializer:XmlSerializer /datacontractonly 给出以下错误,这就是我要求替代工具的原因。
svcutil schema.xsd /serializer:XmlSerializer /datacontractonly 错误:命名空间“http://tempuri.org/XMLSchema.xsd”中的类型“B”不能 被进口。不支持通过限制派生的复杂类型。 要么更改架构,以便类型可以映射到数据协定 类型或使用 ImportXmlType 或使用不同的序列化程序。
如果您使用 /dataContractOnly 选项导入数据合同 类型并收到此错误消息,请考虑使用 xsd.exe 反而。 xsd.exe 生成的类型可以在 Windows 中使用 应用后的通信基础 服务合同上的 XmlSerializerFormatAttribute 属性。 或者,考虑使用 /importXmlTypes 选项导入 这些类型作为 XML 类型与 DataContractFormatAttribute 一起使用 服务合同上的属性。
使用 xsd schema.xsd /c 给出一个类型 B,它继承了 A 而没有隐藏 element1:
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://tempuri.org/XMLSchema.xsd")]
[System.Xml.Serialization.XmlRootAttribute("request", Namespace="http://tempuri.org/XMLSchema.xsd", IsNullable=false)]
public partial class B : A
/// <remarks/>
[System.Xml.Serialization.XmlIncludeAttribute(typeof(B))]
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://tempuri.org/XMLSchema.xsd")]
public partial class A
private string element1Field;
private string element2Field;
/// <remarks/>
public string element1
get
return this.element1Field;
set
this.element1Field = value;
/// <remarks/>
public string element2
get
return this.element2Field;
set
this.element2Field = value;
【问题讨论】:
您不理解该错误消息的哪一部分?它告诉你如何解决这个问题。 不,它没有给我想要的结果(另请注意,我说的消息是 - 这只是一个样本 - 我知道的一个可怜的......)。如果您尝试使用这些选项,您将看到它不会生成具有相关属性的代理。结果是我最终不得不直接处理元素列表和序列化。 我没有兴趣尝试这些选项。 你已经尝试过了,并且你知道结果。请向我们展示您尝试了什么,然后向我们展示结果。 【参考方案1】:错误消息告诉您要么使用/importXmlTypes
开关,要么改为使用XmlSerializer。来自帮助:
/importXmlTypes - 配置数据协定 用于导入非数据协定类型的序列化程序 作为 IXmlSerializable 类型。
和
/serializer:XmlSerializer - 生成使用 XmlSerializer 用于序列化和 反序列化
【讨论】:
是的,我知道,但这样做并没有给我想要的结果,即 B 类型只包含名为 element2 的属性。 “这样做?”做我向你展示的两件件中的哪一件?结果如何?用您所做的研究更新您的问题并向我们展示结果。以上是关于如何使用 svcutil 从使用限制隐藏元素的 Web 服务生成 C# WCF 代理?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Selenium WebDriver 从隐藏元素中读取文本?