WCF 客户端的可选枚举
我正在使用外部供应商的 Web 服务,该服务似乎是用 Java 实现的(我相信是 Apache Axis),并且我正在使用 WCF 客户端使用它。有几个操作需要枚举类型的输入参数。问题是他们只希望在某些情况下传递枚举。这些元素在 WSDL 中未标记为可为空。不过,由于它们是枚举,即使未指定,我的 WCF 客户端也将始终传递默认值。此行为导致其服务出现内部错误。
关于如何解决这个问题有什么想法吗?最好是不需要手动修改代理的解决方案,因为如果其他开发人员将来独立生成它,这可能会导致混乱。
特定元素在 WSDL 中指定如下:
<xs:complexType name="complexTypeName">
<xs:sequence>
<!-- More Stuff Here-->
<xs:element minOccurs="0" name="parameterName" type="tns:parameterName" />
<!-- More Stuff Here-->
</xs:sequence>
</xs:complexType>
<!-- . . . -->
<xs:simpleType name="parameterName">
<xs:restriction base="xs:string">
<xs:enumeration value="ONLY_AVAILABLE_VALUE" />
</xs:restriction>
</xs:simpleType>
Svcutil 将其翻译为
[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://vendorwebservicenamespace.com/")]
public enum parameterName
{
/// <remarks/>
ONLY_AVAILABLE_VALUE,
}
编辑: 经过更多研究,看起来 svcutil 应该 通常会生成可选参数 (minOccurs=0)带有附加的 bool
fieldNameSpecified 参数,允许调用者指示该字段是否应该被序列化(这记录在此处,此处,以及 此处)。
然而,在这种情况下,参数引用如下:
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://vendorservicenamespace.com/", Order=23)]
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public Namespace.parameterName parameterName;
当我尝试手动添加适当的 fieldNameSpecified 方法时,它似乎对序列化没有任何影响(即参数仍然是出现在肥皂消息中)。
此时,我想知道
- 为什么 svcutil 不包含 fieldNameSpecified 参数?
- 为什么手动添加参数似乎不起作用?
- 对于此问题还有其他解决方法吗?
编辑:经过更多研究,我确定部分问题在于 WSDL 的编写方式。供应商的 WSDL 不符合 DataContractSerializer 的架构参考。因此,svcutil 故障返回到 XmlSerializer。
问题在于它仍在为方法生成消息契约,而不是数据契约。这似乎会导致默认情况下不可为空的任何类型出现问题,因为它们无法从消息中排除(任何人都可以验证这一点吗?)。无论出于什么原因,当用 MessageBodyMemberAttribute
标记参数时,XmlSerializer 的 parameterNameSpecified 方法似乎被忽略(不知道为什么?)
这是我能够解决的唯一方法此行为是通过使用 svcutil 的 /wrapped
选项实现的。这导致消息契约与实际的序列化参数本身分离。在这种情况下,svcutil确实生成parameterNameSpecified方法,并且XmlSerializer符合它们。
I am working with an external vendor's web service that appears to be implemented in Java (I believe Apache Axis), and I'm consuming it with a WCF client. Several of the operations require input parameters of type enumeration. The problem is that they only want the enums passed in certain cases. The elements are not marked as nillable in the WSDL. Since they are enums,though, my WCF client will always pass the default value even if not specified. This behavior is causing an internal error in their service.
Any thoughts on how to address this issue? Preferably, it would be solution that would not require manual modification of the proxy, as this might result in confusion if another developer were to generate it independently in the future.
The particular element is specified as follows in the WSDL
<xs:complexType name="complexTypeName">
<xs:sequence>
<!-- More Stuff Here-->
<xs:element minOccurs="0" name="parameterName" type="tns:parameterName" />
<!-- More Stuff Here-->
</xs:sequence>
</xs:complexType>
<!-- . . . -->
<xs:simpleType name="parameterName">
<xs:restriction base="xs:string">
<xs:enumeration value="ONLY_AVAILABLE_VALUE" />
</xs:restriction>
</xs:simpleType>
Svcutil translates this as
[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://vendorwebservicenamespace.com/")]
public enum parameterName
{
/// <remarks/>
ONLY_AVAILABLE_VALUE,
}
EDIT: After a bit more research, it looks like svcutil should normally generate optional parameters (minOccurs=0) with an additional bool
fieldNameSpecified parameter, allowing the caller to indicate whether or not the field should be serialized (this is documented here, here, and here).
In this case, however, the parameter is referenced as follows:
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://vendorservicenamespace.com/", Order=23)]
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public Namespace.parameterName parameterName;
When I try to manually add the appropriate fieldNameSpecified method, it doesn't seem to have any affect on the serialization (i.e., the parameter is still presents in the soap message).
At this point, I am wondering
- Why isn't svcutil including the fieldNameSpecified parameters?
- Why doesn't adding the parameter manually seem to work?
- Are there any other workarounds available for this issue?
EDIT: After yet more research, I've determined that part of the issue is the way in which the WSDL is written. The Vendor's WSDL does not conform to the Schema Reference for the DataContractSerializer. Because of this, svcutil is failing back to the XmlSerializer.
The problem is that it is still generating the message contracts for the methods, but not the data contracts. This appears to result in a problem for any types that are not nullable by default, in that they cannot be excluded from the message (can anyone verify this?). Whatever reason the parameterNameSpecified method for the XmlSerializer appears to be ignored when a parameter is flagged with the MessageBodyMemberAttribute
(not sure why?)
The only way I have been able to get around this behavior is by using the /wrapped
option with svcutil. This results in message contracts being separated from the actual seralized parameters themselves. In this case, svcutil does generate the parameterNameSpecified methods, and the XmlSerializer conforms to them.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
研究该问题后,我找到的唯一解决方案是使用 svcutil 上的 /wrapped 选项生成代理。正如上面问题中提到的,这增加了一个额外的抽象层,并允许消息契约存在于参数之上的一层。在这种情况下,XmlSerializer 确实生成 fieldNameSpecified 属性并遵守它们。
After researching the issue, the only solution that I've been able to find is to generate the proxy using the /wrapped option on svcutil. As referenced above in the question, this adds an additional layer of abstraction and allows the message contracts to exist a layer above the parameters. In this case the XmlSerializer does generate the fieldNameSpecified properties and conforms to them.