Exporting WSDL/XSD schemas for data contract types with IXmlSerializable
I'm creating a WCF service which I want to consume from a Java app. But the question isn't about .net-java interop.
The key point is one of types related to a service operation is IXmlSerializable. That type return its XSD schema with static method referenced by XmlSchemaProviderAttribute. The problem is when we get wsdl for the service through mex-endpoint (http://..svc?wsdl) that schema isn't returned.
Here're the details.
Some wcf service contract:
[ServiceContract]
public interface IService1
{
[OperationContract]
DomainData GetData();
}
DomainData type is:
[DataContract(Namespace = "http://schemas.biz.org/Samples/customserialization")]
public class DomainData
{
[DataMember(Name = "AuxData")]
Dictionary<String, AuxDomainData> m_auxData = new Dictionary<string, AuxDomainData>();
[DataMember]
public string ObjectId { get; set; }
public IDictionary<string, AuxDomainData> AuxData
{
get { return m_auxData; }
}
}
As you can see DomainData contains a dictionary of AuxDomainData objects, which is:
[XmlSchemaProvider("GetXmlSerializationSchema")]
public class AuxDomainData : IXmlSerializable
{
[DataMember]
public Object AuxData { get; set; }
XmlSchema IXmlSerializable.GetSchema() { return null; }
void IXmlSerializable.ReadXml(XmlReader reader) { }
void IXmlSerializable.WriteXml(XmlWriter writer) { }
public static string Namespace = "http://schemas.biz.org/Samples/customserialization";
public static XmlQualifiedName GetXmlSerializationSchema(XmlSchemaSet schemas)
{
var qname = new XmlQualifiedName("AuxDomainData", Namespace);
string resourceName = "CustomSerialization.aux-domain-data.xsd";
using (Stream stream = typeof(AuxDomainData).Assembly.GetManifestResourceStream(resourceName))
{
var schema = XmlSchema.Read(stream, null);
schemas.Add(schema);
}
return qname;
}
}
Here we're returning XSD schema in GetXmlSerializationSchema method. Schema itself is simple but let me skip it here.
That code is straightforward I guess, it's common scenario for IXmlSerializable types.
Now, we want WSDL. I'm going to use WSDL for creating a Java client with help of Metro But actually JDK 1.6 is enough as it contains WS stack (and wsimport.exe). So java wants wsdl with wsdl:service definition. That's why I can't give it a wsdl from wsdl.exe (because a wsdl produced by wsdl doesn't contain wsdl:service definition, only wsdl:portType). So, I call wsimport.bat http://localhost/Service1.svc?wsdl
But what I get in respose is : [ERROR] undefined simple or complex type 'q1:AuxDomainData' line 1 of http://locahost/CustomSerialization/Service1.svc?xsd=xsd3
That's because a composed wsdl actually doesn't contain such type as AuxDomainData. That's true and we can't blame java/metro/any other stack. If we look at wsdl produced by wcf it contains wsdl:types element with imports of all xsd schemas:
<wsdl:types>
<xsd:schema targetNamespace="http://tempuri.org/Imports">
<xsd:import schemaLocation="http://localhost/CustomSerialization/Service1.svc?xsd=xsd0" namespace="http://tempuri.org/" />
<xsd:import schemaLocation="http://localhost/CustomSerialization/Service1.svc?xsd=xsd1" namespace="http://schemas.microsoft.com/2003/10/Serialization/" />
<xsd:import schemaLocation="http://localhost/CustomSerialization/Service1.svc?xsd=xsd2" namespace="http://schemas.biz.org/Samples/customserialization" />
<xsd:import schemaLocation="http://localhost/CustomSerialization/Service1.svc?xsd=xsd开发者_如何学运维3" namespace="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
</xsd:schema>
</wsdl:types>
I wont' provide all xsd here but the point is there is no AuxDomainData definition in they. The xsd-schema for AuxDomainData type is in http://localhost/CustomSerialization/Service1.svc?xsd=xsd4 "document". But as you can see the root wsdl doesn't contain a reference to it. That's the problem. The result wsdl/xsd schema set isn't complete.
So, what are my options?
Are you sure that the WSDL doesn't reference it? Normally, WCF will include an element just before the list of <wsdl:message> elements, sort of like this:
<wsdl:types>
<xsd:schema targetNamespace="http://tempuri.org/Imports">
<xsd:import schemaLocation="http://localhost/CustomSerialization/Service1.svc?xsd=xsd0" namespace="http://tempuri.org/"/>
<xsd:import schemaLocation="http://localhost/CustomSerialization/Service1.svc?xsd=xsd1" namespace="http://schemas.microsoft.com/2003/10/Serialization/"/>
<xsd:import schemaLocation="http://localhost/CustomSerialization/Service1.svc?xsd=xsd2" namespace="http://schemas.datacontract.org/2004/07/MyServiceNamespace"/>
<xsd:import schemaLocation="http://localhost/CustomSerialization/Service1.svc?xsd=xsd3" namespace="http://schemas.datacontract.org/2004/07/MyServiceNamespace.AnotherNamespace"/>
<xsd:import schemaLocation="http://localhost/CustomSerialization/Service1.svc?xsd=xsd4" namespace="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
</xsd:schema>
</wsdl:types>
Check for this. It should be there. It's possible, however, that Java isn't recognizing it.
If that is the problem, then there are ways to flatten the WSDL. You might try that.
By the way, the mex endpoint is generally Service1.svc/mex. WSDL is slightly different.
Actually, the proposed by Aaron solution from "http://blogs.msdn.com/dotnetinterop/archive/2008/09/23/flatten-your-wsdl-with-this-custom-servicehost-for-wcf.aspx" turns to be not fully correct. Not idea itself, but the code. After using that ExportExtension for several services asking wsdl for next in turn service fails with reason of types dublication.
I also asked on msdn forum: http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/0ea27bec-08cc-4a20-86ce-6e3477abb1c5.
精彩评论