Client no longer getting data from Web Service after introducing targetNamespace in XSD
Sorry if there is way too much info in this post – there’s a load of story before I get to the actual problem. I thought I‘d include everything that might be relevant as I don’t have much clue what is wrong.
I had a working web service and client (both written with VS 2008 in C#) for passing product data to an e-commerce site. The XSD started like this:
<xs:schema id="Ecommerce"
elementFormDefault="qualified"
xmlns:mstns="http://tempuri.org/Ecommerce.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="eur">
<xs:complexType>
<xs:sequence>
<xs:element ref="sec" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
etc
Here’s a sample document sent from client to service:
<eur xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" class="ECommerce_WebService" type="product" method="GetLastDateSent" chunk_no="1" total_chunks="1" date_stamp="2010-03-10T17:16:34.523" version="1.1">
<sec guid="BFBACB3C-4C17-4786-ACCF-96BFDBF32DA5" company_name="Company" version="1.1">
<data />
</sec>
</eur>
Then, I had to give the service a targetNamespace. Actually I don’t know if I “had” to set it, but I added (to the same VS project) some code to act as a client to a completely unrelated service (which also had no namespace), and the project would not build until I gave my service a namespace.
Now the XSD starts like this:
<xs:schema id="Ecommerce"
elementFormDefault="qualified"
xmlns:mstns="http://tempuri.org/Ecommerce.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.company.com/ecommerce"
xmlns:ecom="http://www. company.com/ecommerce">
<xs:element name="eur">
<xs:complexType>
<xs:sequence>
<xs:element ref="ecom:sec" minOccurs="1" maxOccurs="1" />
</xs:sequence>
etc
As you can see above I also updated all the xs:element ref attributes to give them the “ecom” prefix. Now the project builds again.
I found the client needed some modification after this. The client uses a SQL stored procedure to generate the XML. This is then de-serialised into an object of the correct type for the service’s “get_data” method. The object’s type used to be “eur” but after updating the web reference to the service, it became “get_dataEur”. And sure enough the parent element in the XML had to be changed to “get_dataEur” to be accepted. Then bizarrely I also had to put the xmlns attribute containing my namespace on the “sec” 开发者_StackOverflow社区element (the immediate child of the parent element) rather than the parent element. Here’s a sample document now sent from client to service:
<get_dataEur xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" class="ECommerce_WebService" type="product" method="GetLastDateSent" chunk_no="1" total_chunks="1" date_stamp="2010-03-10T18:23:20.653" version="1.1">
<sec xmlns="http://www.company.com/ecommerce" guid="BFBACB3C-4C17-4786-ACCF-96BFDBF32DA5" company_name="Company" version="1.1">
<data />
</sec>
</get_dataEur>
If in the service’s get_data method I then serialize the incoming object I see this (the parent element is “eur” and the xmlns attribute is on the parent element):
<eur xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.company.com/ecommerce" class="ECommerce_WebService" type="product" method="GetLastDateSent" chunk_no="1" total_chunks="1" date_stamp="2010-03-10T18:23:20.653" version="1.1">
<sec guid="BFBACB3C-4C17-4786-ACCF-96BFDBF32DA5" company_name="Company" version="1.1">
<data />
</sec>
</eur>
The service then prepares a reply to go back to the client. The XML looks like this (the important data being sent back is the date_stamp attribute in the last_sent element):
<eur xmlns="http://www.company.com/ecommerce" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" class="ECommerce_WebService" type="product" method="GetLastDateSent" chunk_no="1" total_chunks="1" date_stamp="2010-03-10T18:22:57.530" version="1.1">
<sec version="1.1" xmlns="">
<data>
<last_sent date_stamp="2010-02-25T15:15:10.193" />
</data>
</sec>
</eur>
Now finally, here’s the problem!!! The client does not see any data – all it sees is the parent element with nothing inside it. If I serialize the reply object in the client code it looks like this:
<get_dataResponseEur xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" class="ECommerce_WebService" type="product" method="GetLastDateSent" chunk_no="1" total_chunks="1" date_stamp="2010-03-10T18:22:57.53" version="1.1" />
So, my questions are:
why isn’t my client seeing the contents of the reply document?
how do I fix it?
why do I have to put the xmlns attribute on a child element rather than the parent element in the outgoing document?
Here’s a bit more possibly relevant info:
The client code (pre-namespace) called the service method like this:
XmlSerializer serializer = new XmlSerializer(typeof(eur));
XmlReader reader = xml.CreateReader();
eur eur = (eur)serializer.Deserialize(reader);
service.Credentials = new NetworkCredential(login, pwd);
service.Url = url;
rc = service.get_data(ref eur);
After the namespace was added I had to change it to this:
XmlSerializer serializer = new XmlSerializer(typeof(get_dataEur));
XmlReader reader = xml.CreateReader();
get_dataEur eur = (get_dataEur)serializer.Deserialize(reader);
get_dataResponseEur eur1 = new get_dataResponseEur();
service.Credentials = new NetworkCredential(login, pwd);
service.Url = url;
rc = service.get_data(eur, out eur1);
After the namespace was added I had to change it to this:
You don't seem to add any namespace here...... try adding the default namespace to the constructor of the XmlSerializer like this:
XmlSerializer serializer = new XmlSerializer(typeof(get_dataEur), "http://www.company.com/ecommerce"
);
XmlReader reader = xml.CreateReader();
get_dataEur eur = (get_dataEur)serializer.Deserialize(reader);
get_dataResponseEur eur1 = new get_dataResponseEur();
service.Credentials = new NetworkCredential(login, pwd);
service.Url = url;
rc = service.get_data(eur, out eur1);
Does that help??
精彩评论