如何使用 svcutil 从使用限制来隐藏元素的 Web 服务生成 C# WCF 代理?
我正在创建一个或多或少超出我控制范围的 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 和类型 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 级别上工作是不可取的,并且会迫使我们编写包装器。从一开始就手动编写代理代码会更容易。
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 给出继承 A 的类型 B,而不隐藏 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;
}
}
}
I'm creating a client to a web service that is more or less out of my control. Here is a simplified sample of the schema:
<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>
In short we have an object A that contains all elements. The service has several types based on A but with restrictions so that the inherited types are usually smaller than the base type - here exemplified by the type B.
In schema viewers like the one in Visual Studio 2010, SoapUI, etc. this looks as expected. A has 2 elements and B only 1 (= element 2).
By using svcutil I get the full set of elements in both my types A & B, or when playing with the options I get error messages such as:
Error: Type 'B' in namespace 'http://tempuri.org/XMLSchema.xsd' cannot be imported. Complex types derived by restriction
not supported. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a
different serializer.
Hiding fields/properties in inherited types is not a practice/road I like to travel but if I cannot get the provider to change the WSDL it seems I have to do it that way.
Is there alternatives to svcutil that handle this properly or do I have to hand-code my proxies?
Update 1
As pointed out by John Saunders I have not shown the results of the suggestions from svcutil. That was partly to keep the post short... but here goes:
svcutil schema.xsd /importXmlTypes /datacontractonly results in:
[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;
}
}
Working on an Xml-level is not desirable and would force us to write a wrapper. It's easier to handcode the proxy from the getgo.
svcutil schema.xsd /serializer:XmlSerializer /datacontractonly Gives the error below and is the reason I'm asking for alternative tools.
svcutil schema.xsd /serializer:XmlSerializer /datacontractonly
Error: Type 'B' in namespace 'http://tempuri.org/XMLSchema.xsd' cannot
be imported. Complex types derived by restriction not supported.
Either change the schema so that the types can map to data contract
types or use ImportXmlType or use a different serializer.If you are using the /dataContractOnly option to import data contract
types and are getting this error message, consider using xsd.exe
instead. Types generated by xsd.exe may be used in the Windows
Communication Foundation after applying the
XmlSerializerFormatAttribute attribute on your service contract.
Alternatively, consider using the /importXmlTypes option to import
these types as XML types to use with DataContractFormatAttribute
attribute on your service contract.
Using xsd schema.xsd /c gives a type B that inherits A without hiding 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;
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
该错误消息告诉您要么使用
/importXmlTypes
开关,要么更改为使用 XmlSerializer。来自帮助:和
The error message is telling you to either use the
/importXmlTypes
switch, or to change to using the XmlSerializer. From the help:and