We have a SOAP Web Service consumed both by C# and Java clients.
The problem is that clients do not hurry to regenerate their proxies when we upgrade the Web Service and hence a proxy code generated for an older version may be used to consume a newer version of the service.
It so happens, that adding a new property to a response object breaks the Java clients using the already generated old proxy code. Apparently, Java is very strict in its interpretation of WSDL and fails with an exception when a property arrives that does not exist in the WSDL. At least, this is what we observe with the proxy code generated by the apache axis. C# clients are fine - the new properties are simply ignored.
I am trying to figure out how to solve this problem. One solution which seems to be viable is to inject an xsd:any
property into each and every response object found in the WSDL. From what I understand, the various Java implementations are going to use it as a "catch-all" property for all the unknown properties (of course, clients will have to regenerate their proxies to consume these xsd:any definitions, but once done new properties would seize to break their code)
The question is how can I sort of inject these xsd:any
properties in the WSDL without actually adding real "catch-all" properties to the response objects?
Our Web Services are implemented using WCF.
Apparently, the only way to achieve it is by introducing a new endpoint behavior which also implements the IWsdlExportExtension
interface. So, here we go:
public class WSDLFilterBehavior : IWsdlExportExtension, IEndpointBehavior
{
public void ExportContract(WsdlExporter exporter, WsdlContractConversionContext context)
{
// never called
}
public void ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)
{
var schemas = exporter.GeneratedXmlSchemas.Schemas(@"http://Abc/Services/Data");
foreach (XmlSchema schema in schemas)
{
for (int i = schema.Items.Count - 1; i >= 0; --i)
{
// Do some other processing ...
var schemaComplexType = schema.Items[i] as XmlSchemaComplexType;
if (schemaComplexType == null)
{
continue;
}
XmlSchemaSequence xmlSchemaSequence;
var xmlSchemaContentModel = schemaComplexType.ContentModel;
if (xmlSchemaContentModel == null)
{
if (schemaType.Name.StartsWith("ArrayOf"))
{
continue;
}
xmlSchemaSequence = schemaComplexType.Particle as XmlSchemaSequence;
}
else
{
var xmlSchemaComplexContentExtension = xmlSchemaContentModel.Content as XmlSchemaComplexContentExtension;
if (xmlSchemaComplexContentExtension == null)
{
continue;
}
xmlSchemaSequence = xmlSchemaComplexContentExtension.Particle as XmlSchemaSequence;
}
if (xmlSchemaSequence == null)
{
continue;
}
var xmlSchemaObject = new XmlSchemaAny
{
MinOccurs = 0
};
xmlSchemaSequence.Items.Add(xmlSchemaObject);
}
}
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
// not needed
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
// not needed
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint,EndpointDispatcher dispatcher)
{
// not needed
}
public void Validate(ServiceEndpoint endpoint)
{
// not needed
}
}
And it works, it injects the xs:any
(not xsd:any
, but I suppose it is the same) in all the elements, except those that do not derive from any other type and start with "ArrayOf".