Possible bug with XML namespaces

Sep 28, 2009 at 3:54 PM
Edited Sep 28, 2009 at 4:07 PM

Hi,

As per my previous post, I have been experimenting with this tool and I like it alot. I have encountered an issue though, which I would like clarification on. I think it is a bug but I am open to ideas.

I have defined a very simple WCF service to experiment with. The XSDs for this service types are as follows:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="Order"
    targetNamespace="http://schemas.acme.com/Order"
    elementFormDefault="qualified"
    xmlns="http://schemas.acme.com/Order"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:complexType name="Order">
    <xs:sequence>
      <xs:element name="Id" type="xs:integer" />
      <xs:element name="Date" type="xs:dateTime" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="OrderService"
    targetNamespace="http://schemas.acme.com/OrderService"
    elementFormDefault="qualified"
    xmlns="http://schemas.acme.com/OrderService"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:order="http://schemas.acme.com/Order">
  <xs:import namespace="http://schemas.acme.com/Order" schemaLocation=".\Order.xsd" />
  <xs:element name="CreateRequest">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Order" type="order:Order" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="CreateResponse">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="OrderId" type="xs:integer" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Notice the XML namespaces are "http://schemas.acme.com/Order" and "http://schemas.acme.com/OrderService".

The idea is that the "../OrderService" namespace contains the types specific to the Order Service and "../Order" namespace contains the "Order" type that can be re-used across different services and between different systems.

The service definition is as follows:

    [ServiceContract(Namespace = "http://schemas.acme.com/WscfBlue/OrderService")]
    public interface IOrderService
    {
        [OperationContract]
        CreateResponse Create(CreateRequest createRequest);
    }

However, when I generate the contracts using WSCF.blue, the resulting WSDL (and associated schemas) put the "Order" type (and the CreateRequest/CreateResponse types) in a generated namespace. In my case the namespace is "http://schemas.datacontract.org/2004/07/Acme.WscfBlue.Services.Contracts.OrderService". This is obviously not the XML namespace specified in the original schemas. Note that WSCF.blue has applied the following to the Order class...

[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.acme.com/Order", TypeName="Order")]

...but this is ignored. This seems to be down to the behaviour of the XML Serializer. There is a related post on Stack Overflow here: http://stackoverflow.com/questions/649913/how-to-customize-wcf-xml-serialization.

I can get my "Order" type into the "http://schemas.acme.com/Order" namespace but only by applying the "DataContract" attribute to the "Order" class e.g.

[DataContract(Namespace = "http://schemas.acme.com/Order")]

Unfortunately, there are two problems with this. Firstly, I would have to edit generated code which goes against the grain (and everytime I regenerate I have to re-apply the manual fixes). I could add the attribute to a partial class declaration but this links to the second problem. As soon as I add the "DataContract" attribute, an alternative serializer is used which does not serialize class members by default. I would than have to add the "DataMember" to each member I want to be serialized. This is onerous and again, I'm having to manually fix-up generated code.

I think this is a genunie problem, my recommendation for fixing is to have an option in WSCF.blue to have the "DataContract" and "DataMember" attributes applied to the generated code. If each public property has the "DataMember" applied, this is the same net result as the current behaviour but with the benefit of fine grained control over your XML namespaces. There is an added benefit that the Data Contract serializer performs better than the default XML Serializer.

I currently have some bandwidth, I'd volunteer to some time fix this and my other issue regarding StyleCop (http://wscfblue.codeplex.com/WorkItem/View.aspx?WorkItemId=8837) if you welcome contributions.

Thanks,

Callum

Sep 29, 2009 at 12:27 PM

I should probably qualify, I'm not generating from a WSDL. I'm generating the "core" contracts from XSDs only.

When I say "core" contracts, I mean the parameters for the WCF service interfaces.

I'm defining the actual service interface and service implementation myself in C# code.

Thanks,

Callum

Developer
Oct 2, 2009 at 8:07 AM

Hi Callum,

Where are you seeing the namespace "http://schemas.datacontract.org/2004/07/Acme.WscfBlue.Services.Contracts.OrderService"? You mention that the namespace "http://schemas.acme.com/Order" found on the Order type is being ignored. Can you please be more specific about what is ignoring this namespace?

Also, I am a little confused as you mentioned something about the resulting WSDL in your first post, but then mention that you are not generating from WSDL in the second. Do you have a WSDL file and are you using it in anyway?

We have intentionally used the XmlSerializer and not the DataContractSerializer due to its lack of flexiblity. Please see Christian's response in this thread: http://wscfblue.codeplex.com/Thread/View.aspx?ThreadId=70702

Cheers,

Alex.

Oct 2, 2009 at 9:05 AM

Hi Alex,

Thanks for your reply.

Ignored Namespace explanation

If I drill down into my service definition presented by the WCF plumbing (e.g. http://localhost/Acme.WscfBlue.Web.Services/Order.svc?xsd=xsd2), The following schema has been generated by the WCF plumbing and is imported into the WSDL for the OrderService:

<?xml version="1.0" encoding="utf-8" ?>
<xs:schema 
  elementFormDefault="qualified" 
  targetNamespace="http://schemas.datacontract.org/2004/07/Acme.WscfBlue.Services.Contracts.OrderService" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:tns="http://schemas.datacontract.org/2004/07/Acme.WscfBlue.Services.Contracts.OrderService">
  <xs:import 
    schemaLocation="http://localhost/Acme.WscfBlue.Web.Services/Order.svc?xsd=xsd3" 
    namespace="http://schemas.datacontract.org/2004/07/System.ComponentModel" />
  ...
  <xs:complexType name="Order">
    <xs:sequence>
      <xs:element name="PropertyChanged" nillable="true" type="q2:PropertyChangedEventHandler" 
                  xmlns:q2="http://schemas.datacontract.org/2004/07/System.ComponentModel" />
      <xs:element name="dateField" type="xs:dateTime" />
      <xs:element name="idField" nillable="true" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
  <xs:element name="Order" nillable="true" type="tns:Order" />
  ...
</xs:schema>

Note that the XML namespace for this schema is "http://schemas.datacontract.org/2004/07/Acme.WscfBlue.Services.Contracts.OrderService" and this schema contains my "Order" type. This means that Order is not in the namesapce of "http://schemas.acme.com/Order" as specified by the original schema I used to generate the Operation Contract item. As per above, WSCF.blue is applying this attribute to the Order class:

[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.acme.com/Order", TypeName="Order")]

...but this is ignored. As per above, this seems to be down to the behaviour of the XML Serializer. Related post on Stack Overflow here: http://stackoverflow.com/questions/649913/how-to-customize-wcf-xml-serialization (same as link in original post above).

 WSDL use explanation

With regards to the WSDL, I'm not generating the wole service defintion from a WSDL. I am generating the "OperationContract" parameters from XSDs (Order and OrderService schemas above). I'm then manually writing my "ServiceContract" to use those objects.

The reason for this is that in my case I'm not too bothered about the WSDL, I'm only really concerned with the schemas representing the "OperationContract" parameters. For example, I want to re-use the "Order" type between services, this means I need strict control over the namepaces. Obviously the Order type in the namespace "http://schemas.datacontract.org/2004/07/Acme.WscfBlue.Services.Contracts.OrderService" is not equivalent the Order type in the namespace "http://schemas.acme.com/Order".

Let me know your thoughts.

Thanks,

Callum

Coordinator
Oct 2, 2009 at 9:16 AM

Try adding
[XmlSerializerFormat]

to your ServiceContract interface.

 

Thanks,
Christian

Oct 2, 2009 at 12:08 PM

Adding the "XmlSerializerFormat" attribute works great. The WSDL and XSDs generated by the WCF plumbing are also much, much cleaner.

Thanks for your assistance.

Regards,

Callum