Showing posts with label XML Schema. Show all posts
Showing posts with label XML Schema. Show all posts

Friday, February 12, 2010

Quiz #1 - the answer

@YaronNaveh

Quiz #1 is over. Pablo and Dmitry were right, the XmlWriter uses the builder design pattern. A common algorithm traverses over the xml nodes, while a concrete builder (derived from XmlWriter) builds the resulting object (the stream) in a concrete way. This allows multiple builders (xml text writer, xml binary writer) to be used.

@YaronNaveh

What's next? get this blog rss updates or register for mail updates!

Saturday, January 23, 2010

Schema repository on your machine

@YaronNaveh

Sometimes it is useful to look at some of the known xsd schemas. These schemas are the xsd schema itself, the soap schema, the schema of wsdl and much more.
If you have VS 2008 installed then check out this folder:


%Program Files%\Microsoft Visual Studio 9.0\Xml\Schemas


It contains all of these schemas and more.

@YaronNaveh

What's next? get this blog rss updates or register for mail updates!

Wednesday, April 29, 2009

Interoperability Gotcha: Visual Studio 2008 Proxy Flavours

@YaronNaveh

The following interoperability issue can happen with a .Net 3.5 clients and older web services from various platforms (including Java. and .Net)

Everyone knows that Visual Studio 2008 has a build-in support for WCF which is the latest generation of Microsoft soap stack. By default, when writing web service clients in VS 2008 a WCF-flavored proxy is generated. However WCF only supports a subset of XML schema and WSDL patterns. For example it does not support RPC/Encoded WSDLs and XML attributes. Many older WSDLs use RPC/Encoded. With such WSDLs WCF is supposed to gracefully downgrade itself to .Net 2.0 which does support these WSDLs. I have noticed that in some cases this does not happen correctly. The result can be web service methods returning null instead of values.

The solution for such cases is to manually instruct VS 2008 to use its backward compatible proxy. All you need to do is:

1. Press the "Add Service Reference" as usual



2. Press the "Advanced..." button



3. Select "Add Web Reference..."



4. Use the good old .Net 2.0 proxy flavours

@YaronNaveh

What's next? get this blog rss updates or register for mail updates!

Thursday, March 12, 2009

OpenGIS With .Net 2.0 And WCF

@YaronNaveh

Geospatial and location based services became very popular these days. One concern for developers of such applications is how to represent the data in the system. This includes simple data types such as points or coordinate systems and complex ones such as advanced topologies. The correct approach is of course to use types from the standard schema set of the Open Geospatial Consortium (OGC).

For a .Net developer this may imply the following needs:

  • Use xsd.exe to generate classes for serizliation


  • Create .Net 2.0 / WCF web services that utilize these schemas


  • Consume Wsdl's with these schemas



  • Unfortunetely the OpenGIS standard schemas are not interoperable with .Net. This has already been noticed by developers for older OpenGIS versions but newer versions seem to be equality incompatible.

    If you only want the fix without the details download it here and see in the end of the post the fix details:




    Here are some of the errors one gets when trying to consume Gml 3.1.1 and Gml 3.2.1 schemas in .Net:

    Gml 3.1.1 - WCF

    While using "add service reference" we get this error:


    Custom tool error: Failed to generate code for the service reference 'ServiceReference1'. Please check other error and warning messages for details.


    And after this an empty proxy code is generated:


    namespace ConsoleApplication1.ServiceReference1 {

    }



    Gml 3.1.1 - .Net 2.0

    The wsdl importing stage seems to work fine. Let's build a one line client:


    WebReference.Service c = new WebReference.Service();



    Such a simple client - what can possibly go wrong? Well nothing, except this:


    "There was an error reflecting property '_ReferenceSystem'."

    "There was an error reflecting type 'ConsoleApplication1.WebReference.AbstractReferenceSystemType'."
    ...

    "There was an error reflecting property 'Item'."
    ...
    "There was an error reflecting property 'Text'."

    "Member 'Text' cannot be encoded using the XmlText attribute. You may use the XmlText attribute to encode primitives, enumerations, arrays of strings, or arrays of XmlNode."


    And this is after I have omitted some inner exceptions.

    In some cases (depending on .Net 2.0 patch level) the below exception will appear - not much improvement:


    Unable to generate a temporary class (result=1).
    error CS0029: Cannot implicitly convert type 'ConsoleApplication70.localhost.LineStringSegmentType' to 'ConsoleApplication70.localhost.LineStringSegmentType[]'
    error CS0029: Cannot implicitly convert type 'ConsoleApplication70.localhost.LineStringSegmentType' to 'ConsoleApplication70.localhost.LineStringSegmentType[]'


    Finally, depending in the types we reference, we might get this one as well:


    There was an error reflecting type 'ConsoleApplication70.localhost.TopoSurfacePropertyType'.


    Gml 3.2.1 - WCF

    Proxy is generated but the simplest client throws this exception chain:


    There was an error reflecting type 'ConsoleApplication1.ServiceReference1.RingPropertyType'.

    "There was an error reflecting type 'ConsoleApplication1.ServiceReference1.RingType'."

    ...

    "Member 'Text' cannot be encoded using the XmlText attribute. You may use the XmlText attribute to encode primitives, enumerations, arrays of strings, or arrays of XmlNode."



    Gml 3.2.1 - .Net 2.0

    Guess what?


    "There was an error reflecting property '_ReferenceSystem'."

    "There was an error reflecting type 'ConsoleApplication1.WebReference.AbstractReferenceSystemType'."

    ...

    "Member 'Text' cannot be encoded using the XmlText attribute. You may use the XmlText attribute to encode primitives, enumerations, arrays of strings, or arrays of XmlNode."


    Why these errors happen?

    The errors appear in run-time when we instantiate the client proxy or web service. At this stage .Net creates the serialization assembly for each type and fails to do it for the proxy. Actually if we have marked the "generate serialization assembly" build option we could already see these errors in compile time.

    Now what?

    We need to fix the schemas or the proxy in order to make them interoperable with .Net. The fix must be compatible with the original schema, so it may change the schema syntax but must result in an isomorphic schema.

    Making Gml 3.2.1 work

    There are two reasons for this schema incomparability:

  • Cyclic schema references



  • From gml.xsd:


    <include schemaLocation="deprecatedTypes.xsd"/>


    From deprecatedTypes.xsd:


    <include schemaLocation="gml.xsd"/>


    One way to solve this is to remove deprecatedTypes.xsd altogether - it is not really required. We'll be nicer and just replace inside it the reference to gml.xsd with these direct references:


    <include schemaLocation="dynamicFeature.xsd"/>
    <include schemaLocation="topology.xsd"/>
    <include schemaLocation="coverage.xsd"/>
    <include schemaLocation="coordinateReferenceSystems.xsd"/>
    <include schemaLocation="observation.xsd"/>
    <include schemaLocation="temporalReferenceSystems.xsd"/>


  • Non-string lists


  • .Net does not support the xsd:list data type. When the list is of strings it works anyway since unresolved types are treated as strings. But for other types it is not supported. MSDN contains some more information on xsd:list support in .Net.

    basicTypes.xsd contains this:


    <simpleType name="doubleList">
       <annotation>
         <documentation>XML List based on XML Schema double type. An element of this type contains a space-separated list of double values</documentation>
       </annotation>
       <list itemType="double" />
    </simpleType>


    Which becomes this in the .Net proxy:


    ///
    [System.Xml.Serialization.XmlTextAttribute()]
    public double[] Value {
      get {
        return this.valueField;
      }
      set {
        this.valueField = value;
      }
    }


    which causes a run-time error since the XmlTextAttribute is only appropriate on strings.

    The solutions is to replace all non-string lists in the schema to strings so the above becomes:


    ...
    <list itemType="string" />
    ...


    And after this Gml 3.2.1 classes are serializable by .Net!


    Making Gml 3.1.1 work

    This version has two issues:

  • Same issue with lists as in 3.2.1 - same fix


  • I've seen this one a couple of times. Basically when there is a multidimensional array of a type which has a single child element in some cases .Net code generation is incorrect. Don't ask, long story... Just replace in geometryPrimitives.xsd:




  • <complexType name="LineStringSegmentArrayPropertyType">
      <sequence>
        <element ref="gml:LineStringSegment" minOccurs="0" maxOccurs="unbounded"/>
      </sequence>
    </complexType>


    With:


    <complexType name="LineStringSegmentArrayPropertyType">
      <sequence>
        <element ref="gml:LineStringSegment" minOccurs="0" maxOccurs="unbounded"/>
        <any />
      </sequence>
    </complexType>


    And we have 3.1.1 working as well!

    Download fix

    I have uploaded the fixed schemas to save your time:



    After you extract the zip the fixed schemas are in the below folders:


    opengis_net_fixed\gml\3.1.1_fixed
    opengis_net_fixed\gml\3.2.1_fixed

    @YaronNaveh

    What's next? get this blog rss updates or register for mail updates!

    Friday, January 30, 2009

    Interoperability Gotcha: Order of XML Elements

    @YaronNaveh

    This time I will talk about the importance of order within xml elements.

    Let's say we have a web service with this schema:


    <s:element name="root">
     <s:complexType>
      <s:sequence>
       <s:element name="elem1" type="s:string" />
       <s:element name="elem2" type="s:string" />
      </s:sequence>
     </s:complexType>
    </s:element">


    So of course this is a valid request:


    <root>
     <elem1>I'm elem1</elem1>
     <elem2>I'm elem2</elem2>
    </root>


    But about about this?


    <root>
     <elem2>I'm elem2</elem2>
     <elem1>I'm elem1</elem1>
    </root>


    This is not a valid xml instance!
    The reason is that the schema contains the element which requires its sub elements to have order.

    So why is it an interoperability gotcha?
    The reason is that different soap stacks by different vendors behave differently in such cases. Sometimes even different stacks of the same vendor are divided...

    Let's see how a .Net 2.0 proxy would look like:


    ...
    private string elem1;
    private string elem2;
    ...


    This proxy can parse both xml instances from above.

    This is how the equivalent WCF proxy would look like:


    [XmlElement(Order=0)]
    public string Elem1
    {
    ...
    }

    [XmlElement(Order=1)]
    public string Elem2
    {
    ...
    }


    This proxy is stricter and actually enforces the order of elements. So it would only accept the first (legal) instance and will give unexpected results with the second. It would usually not throw an exception but rather ignore the message and use default values for the unordered elements so your fields will have a lot of NULL's and zeros.

    How to fix it?

    Option 1 (recommended) - Send XML with the correct order.

    Option 2 - Change the WSDL to use <all> instead of <sequence>. The former does not require correct order of elements (there are some other subtle differences). Note that in case the WSDL is dynamically generated this may be hard to maintain.

    Option 3 - Remove the "Order=..." property from the WCF proxy. Note that when the proxy will be regenerated the "Order" property will come back so this is also a maintenance challenge.

    @YaronNaveh

    What's next? get this blog rss updates or register for mail updates!

    Saturday, October 11, 2008

    Java, WCF & Web Services Interoperability (part 1 of N): Be XML Schema Aware

    @YaronNaveh


    So, you want to write an Axis2 web service and have .Net WCF clients too? Or maybe you already have a .Net 2.0 endpoint and want it to be consumed by WSIT? Yes, that’s possible, but there is some important stuff you should know about. Whether you are a .Net WCF, AXIS2, Metro or any other framework developer/tester – you want to stay tuned for this series.

    This first post deals with XML schema, what you can do with it and – more importantly – what you shouldn’t do with it. I’m not going to preach you on service-first vs. wsdl-first approaches –
    others wrote some good posts on it. I am going to recommend you on some good habits no matter which approach you take.

    DO be aware of your schema
    If you are a wsdl-first type of developer then the schema is the first item you get to be aware of. But even if you prefer working with annotated classes: Be aware of how the different language types and annotations affect your wsdl – you don’t want to find yourself with a non-interoperable wsdl at a late stage.

    DO be aware of schema subsets
    This one is more for Java developers wanting to build service that interoperate with WCF. Microsoft has decided that WCF will support only a subset of the XML schema as a first class member. The main reason is probably to promote simplicity. This subset does NOT include xsd:choice, xsd:attribute and some other very common structures. This is the WCF supported subset – be aware of it!
    One word of restriction is required: Even if you use unsupported schema constructs in your wsdl WCF proxies have a “backward compatible” mode and they “downgrade” themselves to the .Net 2.0 supported schema subset which is larger. So it’s not the end of the world. However for various reasons, including performance and programming model ease of use – try to stick to the WCF supported subset.

    DO ensure schema completeness
    If your schema uses some type – you have to define that type in the schema or reference another schema that defines it. In the past there were some issues with types that one framework could understand internally and that’s why it didn’t put them in the wsdl - causing other frameworks to fail. So whenever you use a system type which is not the simple integer/string/etc. you should ensure its definition appears in the wsdl. For example if you are writing a .Net 2.0 web service and one method looks like this:


    [WebMethod]
    public Guid GenerateId()


    You can notice how the wsdl contains the Guid definition:

    <s:simpleType name="guid">
    <s:restriction base="s:string">
    <s:pattern value="[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}" />
    </s:restriction>
    </s:simpleType>


    Of course the same goes for java types such as maps and vectors – make sure they appear in the wsdl.

    DO NOT use schema types which are known to be problematic
    One example here is xsd:date and xsd:time which are not directly supported by .Net. The .Net framework treats them both as xsd:dateTime so some semantics would get loss.


    That’s it for today. Stay tuned for the following posts in this series. If you have any schema related tips feel free to drop a comment.

    @YaronNaveh

    What's next? get this blog rss updates or register for mail updates!