问题
My team is tasked with getting several in-house developed .NET client applications to connect to some new Java web services. The Java web service is a third party, vendor supplied WSDL file that our team has a limited ability to modify/control...meaning we probably have the power to request our vendor to make slight tweaks to the WSDL, but major changes would probably be either unfeasible or difficult to request.
That said, we are attempting to utilize WCF/.NET 4.0 to generate the .NET proxy class files we need on the client side. The proxy client class file generation process executes without issues.
The problem is when we attempt to use the proxy class file in a client app. I have verified through the web trace tool, Fiddler, that the raw SOAP message request fails to get sent across the wire to the server.
The specific .NET exception message I get when attempting to call the web service method in question, looks like this:
System.InvalidOperationException was unhandled Message=XmlSerializer attribute System.Xml.Serialization.XmlAttributeAttribute is not valid in baseLanguage. Only XmlElement, XmlArray, XmlArrayItem, XmlAnyAttribute and XmlAnyElement attributes are supported when IsWrapped is true. Source=System.ServiceModel
When I examine the .NET autogenerated proxy class file, Reference.cs, I noticed that the request and response messages for my web service method looks something like this:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="QueryPBOT_MXWO_OS", WrapperNamespace="http://www.ibm.com/maximo", IsWrapped=true)]
public partial class QueryPBOT_MXWO_OSRequest {
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=0)]
public ConsoleApplication7.wsMaximo.PBOT_MXWO_OSQueryType PBOT_MXWO_OSQuery;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=1)]
[System.Xml.Serialization.XmlAttributeAttribute()]
public string baseLanguage;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=2)]
[System.Xml.Serialization.XmlAttributeAttribute()]
public string transLanguage;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=3)]
[System.Xml.Serialization.XmlAttributeAttribute()]
public string messageID;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=4)]
[System.Xml.Serialization.XmlAttributeAttribute()]
public string maximoVersion;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=5)]
[System.Xml.Serialization.XmlAttributeAttribute()]
[System.ComponentModel.DefaultValueAttribute(false)]
public bool uniqueResult;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=6)]
[System.Xml.Serialization.XmlAttributeAttribute(DataType="positiveInteger")]
public string maxItems;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=7)]
[System.Xml.Serialization.XmlAttributeAttribute(DataType="integer")]
[System.ComponentModel.DefaultValueAttribute("0")]
public string rsStart;
public QueryPBOT_MXWO_OSRequest() {
}
public QueryPBOT_MXWO_OSRequest(ConsoleApplication7.wsMaximo.PBOT_MXWO_OSQueryType PBOT_MXWO_OSQuery, string baseLanguage, string transLanguage, string messageID, string maximoVersion, bool uniqueResult, string maxItems, string rsStart) {
this.PBOT_MXWO_OSQuery = PBOT_MXWO_OSQuery;
this.baseLanguage = baseLanguage;
this.transLanguage = transLanguage;
this.messageID = messageID;
this.maximoVersion = maximoVersion;
this.uniqueResult = uniqueResult;
this.maxItems = maxItems;
this.rsStart = rsStart;
}
}
I know that people reading this post will want to see the actual WSDL file we're trying to consume, but it is quite large, and I'm concerned the sheer size of it would make pinpointing the error quite difficult.
I'm hoping that the autogenerated client proxy file and the .NET exception will help someone recognize this WCF Serialization issue.
We've confirmed from our Java vendor that the style of WSDL they generate is doc-literal. After doing some research on the internet, it appears that WCF, by default. translates WSDL files with doc-literal wrapped, and that this may explain, at least in part, why we're seeing this WCF serialization issue with the WSDL file.
I've discovered, through trial and error, that the following attribute decorator in the proxy class file is the culprit behind the serialization issue:
[System.Xml.Serialization.XmlAttributeAttribute()]
If I comment out all instances of this attribute in the proxy class file and rerun my client app, the SOAP message successfully gets sent across the wire and I get a valid web service response come back from the server.
This fix is better than nothing, but I would very much prefer a solution that doesn't require myself or anyone on my team to constantly tweak these .NET autogenerated proxy class files.
I would like to know if there is something I can do, either through the various WCF tools or by modifying the WSDL file, that prevents that [System.Xml.Serialization.XmlAttributeAttribute()] from being applied to my request and response object properties?
Or at least a high level description of WHY we are seeing this serialization behavior in .NET with the Java WSDL file?
thanks in advance, John
回答1:
Use svcutil.exe utility with the /wrapped option on to generate proxy classes.
This will create slightly different classes then those created though Visual Studio in a way described by Ladislav Mrnka here. Resulting proxies should be free from the XmlAttribute issue when using on the client side.
Example:
svcutil /t:code wsdl.xml /out:wsdl.cs /serializer:XmlSerializer /wrapped
回答2:
Here is how to do Mikhail G's solution within IDE:
- Open Reference.svcmap under Service References
- Add
<Wrapped>true</Wrapped>
under<ClientOptions>
and Save - Right Click Reference.svcmap and hit "Run Custom Tool"
Visual Studio, where magic happens :)
Note: Tried with VS 2015. Prior versions may have same option with a different name than "Run Custom Tool"
回答3:
Based on generated code it looks like your Java service expects request like:
<s:Envelope xmlns:s="...">
...
<s:Body>
<QueryPBOT_MXWO_OS xmlns="http://www.ibm.com/maximo" baseLanguage="..." transLanguage="..." ...>
<PBOT_MXWO_OSQuery>
...
</PBOT_MXWO_OSQuery>
</QueryPBOT_MXWO_OS>
</s:Body>
</s:Envelope>
The problem is that WCF recognized QueryPBOT_MXWO_OS as wrapper element for request. I'm not sure why it fires exception but probably there is some restriction that wrapper element can't have attributes. I'm suspicious that this is just global error handling shared with version which uses IsWrapped=false where usage of attributes is error.
You can try to modify your proxy in this way:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.MessageContractAttribute(IsWrapped=false)]
public partial class QueryPBOT_MXWO_OSRequest
{
[MessageBodyMemberAttribute(Name="QueryPBOT_MXWO_OS", Namespace="http://www.ibm.com/maximo")]
public QueryPBOT_MXWO_OS QueryPBOT_MXWO_OS { get; set; }
}
[XmlRoot(ElementName="QueryPBOT_MXWO_OS", Namespace="http://www.ibm.com/maximo")]
public class QueryPBOT_MXWO_OS
{
[XmlElement(Namespace="http://www.ibm.com/maximo")]
public ConsoleApplication7.wsMaximo.PBOT_MXWO_OSQueryType PBOT_MXWO_OSQuery;
[XmlAttribute(Namespace="http://www.ibm.com/maximo")]
public string baseLanguage;
[XmlAttribute(Namespace="http://www.ibm.com/maximo")]
public string transLanguage;
[XmlAttribute(Namespace="http://www.ibm.com/maximo")]
public string messageID;
[XmlAttribute(Namespace="http://www.ibm.com/maximo")]
public string maximoVersion;
[XmlAttribute(Namespace="http://www.ibm.com/maximo")]
[System.ComponentModel.DefaultValueAttribute(false)]
public bool uniqueResult;
[XmlAttribute(Namespace="http://www.ibm.com/maximo")]
public string maxItems;
[XmlAttribute(Namespace="http://www.ibm.com/maximo")]
[System.ComponentModel.DefaultValueAttribute("0")]
public string rsStart;
}
回答4:
As a follow-on to stratovarius's answer, in VS 2017 the Service References folder is replaced by Connected Services, so you have to:
- Open the {project}/Connected Services folder in Windows Explorer
- Find and edit the Reference.svcmap with a text editor
- Add
<Wrapped>true</Wrapped>
to the<ClientOptions>
section - Save the file
- In VS, right click on the service reference under Connected Services and select "Update Service Reference"
This cleared the exception from my service call.
来源:https://stackoverflow.com/questions/3840901/wcf-serialization-problems-with-wsdl-file-created-by-java-tools