I use Apache CXF with Aegis data binding to provide a Java web service to a C# client. This works in principle very well. On the C# side, I would like to use the more limited DataContractSerializer, because it allows for collections instead of arrays. I understand using the DataContractSerializer limits the complexity of the Aegis-generated WSDL. Now I have a Java type that uses inheritance. Aegis is able to generate a WSDL that contains both the base and the derived type, but the DataContractSerializer does not seem to be able to understand this WSDL. SvcUtil falls back to the XmlSerializer, and my collections get ugly arrays.
I can imagine thee theoretical possibilities to deal with this issue:
Turn off Inheritance support with Aegis. This should cause the WSDL to contain only the derived types, containing each all of the base type properties.
Somehow make DataContractSerializer understand WSDL inheritance
Somehow make XmlSerializer use collections instead of arrays
I think the last two options are not possible, so I am stuck with the first one. How can I turn off Aegis inheritance?
Example WSDL fragment:
<xsd:schema attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://tables.basic.meona.de">
<xsd:complexType abstract="true" name="BaseTreeNode">
<xsd:sequence>
<xsd:element minOccurs="0" name="active" type="xsd:boolean"/>
<xsd:element minOccurs="0" name="category" type="xsd:boolean"/>
<xsd:element minOccurs="0" name="name" nillable="true" type="xsd:string"/>
<xsd:element minOccurs="0" name="sequenceNumber" nillable="true" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
<xsd:complexType name="EmergencyDiagnosis">
<xsd:complexContent>
<xsd:extension base="ns0:BaseTreeNode">
<xsd:sequence>
<xsd:element minOccurs="0" name="externalCode" nillable="true" type="xsd:string"/>
<xsd:element minOccurs="0" name="favoriteDiagnosis" type="xsd:boolean"/>
<xsd:element minOccurs="0" name="identifier" nillable="true" type="xsd:string"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
It seems former versions of Aegis did not generate the extension, so I am hoping it can be switched off: https://issues.apache.org/jira/browse/CXF-5176
After reading the Aegis source code, I helped myself with the following hack:
public class AegisNonExtensionBeanType extends BeanType {
#Override
public BeanTypeInfo getTypeInfo() {
BeanTypeInfo bti = super.getTypeInfo();
bti.setExtension(false);
bti.setExtensibleAttributes(false);
bti.setExtensibleElements(false);
return bti;
}
#Override
public AegisType getSuperType() {
return null;
}
}
If I register this AegisType for my inherited beans, it works.
Mustn't there be a better way?
Related
I have one XSD file as below:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:gml="http://www.opengis.net/gml" xmlns:njdot="SomeURL" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="SomeURL">
<xsd:import namespace="http://www.opengis.net/gml" schemaLocation="SomeURL/feature.xsd"/>
<xsd:complexType name="StudentType">
<xsd:complexContent>
<xsd:extension base="gml:AbstractfeatureType">
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="1" name="StudentId" nillable="false" type="xsd:decimal"/>
<xsd:element maxOccurs="1" minOccurs="1" name="class_ID" nillable="false" type="xsd:decimal"/>
<xsd:element maxOccurs="1" minOccurs="1" name="Name" nillable="false" type="xsd:string"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="Student" substitutionGroup="gml:_Feature" type="njdot:StudentType"/>
</xsd:schema>
My requirement is : Read this XSD data into c# on flying and Print them to console.
Currently while compiling XSD, I am getting following error:
Undefined complexType 'http://www.opengis.net/gml:AbstractFeatureType' is used as a base for complex type extension.
Error: Reference to undeclared substitution group affiliation.
I think I am not importing the external schema which is given with
Can anyone suggest what can be the solution or how can I achieve my desired output?
Thanks in advance.
I have TCX exercise files which are written using the schema at https://www8.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd. I have been using them for years with Java and JAXB. I am trying to write a C# application to do the same thing. It is not going well. I can generate C# classes using xsd.exe as provided by Visual Studio. However, they do not make sense to me and cannot be used to deserialize my TCX files.
The basic structure of TCX files (at least the part in which I am interested) is they have a number of Activities containing a number of Laps containing a number of Tracks containing a number of Trackpoints. The Trackpoints have latitude, longitude, and heart rate as the main items of interest.
The xsd-generated C# classes have an Activity_t[], an ActivityLap_t[], and a Trackpoint_t[][]. There is no Track_t[] and the string Track_t does not appear in the file even though it is in the .xsd, for example in this excerpt for the Lap and Track.
<xsd:complexType name="ActivityLap_t">
<xsd:sequence>
<xsd:element name="TotalTimeSeconds" type="xsd:double"/>
<xsd:element name="DistanceMeters" type="xsd:double"/>
<xsd:element name="MaximumSpeed" type="xsd:double" minOccurs="0"/>
<xsd:element name="Calories" type="xsd:unsignedShort"/>
<xsd:element name="AverageHeartRateBpm" type="HeartRateInBeatsPerMinute_t" minOccurs="0"/>
<xsd:element name="MaximumHeartRateBpm" type="HeartRateInBeatsPerMinute_t" minOccurs="0"/>
<xsd:element name="Intensity" type="Intensity_t"/>
<xsd:element name="Cadence" type="CadenceValue_t" minOccurs="0"/>
<xsd:element name="TriggerMethod" type="TriggerMethod_t"/>
<xsd:element name="Track" type="Track_t" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="Notes" type="xsd:string" minOccurs="0"/>
<xsd:element name="Extensions" type="Extensions_t" minOccurs="0">
<xsd:annotation>
<xsd:documentation>You can extend Training Center by adding your own elements from another schema here.</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="StartTime" type="xsd:dateTime" use="required"/>
</xsd:complexType>
<xsd:complexType name="Track_t">
<xsd:sequence>
<xsd:element name="Trackpoint" type="Trackpoint_t" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
I don't understand how to deal with the [][] nor why it would be generated. And as mentioned it fails to parse.
error CS0030: Cannot convert type
'TrainingCenterDatabaseV2.Trackpoint_t[] to
TrainingCenterDatabaseV2.Trackpoint_t.
(The namespace I used is TrainingCenterDatabaseV2.)
This is the code used to deserialize:
private const string NS_TrainingCenterDatabase_v2 = "http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2";
XmlSerializer xmlSerializer = new XmlSerializer(typeof(TrainingCenterDatabase_t),
NS_TrainingCenterDatabase_v2);
FileStream fs = new FileStream(fileName, FileMode.Open);
XmlReader reader = XmlReader.Create(fs);
TrainingCenterDatabase_t tcx = (TrainingCenterDatabase_t)xmlSerializer.Deserialize(reader);
Not knowing where to go with this I tried the Visual Studio plugin, xsd2code++. This generates sensible C# classes with List<Activity_t>, List<ActivityLap_t>, and List<Trackpoint_t>. It also does not have Track_t, which seems to be somewhat superfluous.
However, it also fails to parse. I believe the problems here have to do with the lack of annotations it generates, compared to the ones generated from xsd.exe. I believe the problem is that it cannot handle the namespaces without those annotations, but I have seen no way to set options to get around that. As stated, I am not experienced with deserialization in C#. For my current purposes I have implemented reading the TCX files using XDocument rather than deserialization. However, I am curious as to why what I tried did not work, especially since xsd.exe has been around for a long time.
Thanks in advance.
This appears to be a bug with the xsd.exe tool itself. I would recommend using LinqToXsd (requires .NET Core 2.1), which is another Microsoft-developed technology for accessing XML data using an XSD; it's also more advanced than xsd.exe and in my quick testing appears to fully handle the above Garmin training center database schema without issue.
Also if you cannot install .NET Core on your machine, you can use this nuget package instead. The .NET Core version requires .NET Core 2.1 to actually generate code, but that generated code that can be used in an app that targets .NET Framework 4.6.2 and above.
I am trying to generate classes from WSDL using visual studio Developer command prompt for vs2017.
I am using the command :
wsdl.exe xxx.wsdl file.xsd file2.xsd .....
the WSDL is created in Java and I trying to connect to WSDL from c# project but I get always the same problem:
Error: The xxxServicePortBinding binding of namespace 'urn:
xxx3Services-1-1-0' cannot be imported.
- The login process cannot be imported.
- The data type 'urn: xxxxServiceTypes-1-1-0: AuthorizationFilter' does not exist.
I went to xsd "xxxxServiceTypes-1-1-0" and the code of AuthorizationFilter is like:
<xsd:complexType name="DeclareEndpointRequest_Type">
<xsd:annotation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="VUNr" type="omds:VUNr" minOccurs="0"/>
<xsd:element name="BasisUrlEndpoint">
<xsd:annotation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="1000"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element ref="ArtAuthentifizierung"/>
<xsd:element name="Credentials" type="Credentials_Type">
<xsd:annotation>
</xsd:annotation>
</xsd:element>
<xsd:element name="AuthorizationFilter" type="cst:AuthorizationFilter" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
Is there is any tipp that could help me to generat classes from thee WSDL.
The answer was that I should insert the reference of the source of AuthorizationFilter in my project in my case it was the system.web.mvc
We have an xsd schema that outlines all the possible data elements in our system, some are simple type elements and some are complex types. We gave this schema to another developer who will try to write up a web service using SOAP. The xsd in a dumb down sample looks like this.
<xs:element name="Element1"> .... </xs:element>
<xs:element name="Element2"> .... </xs:element>
<xs:element name="Element3"> .... </xs:element>
<xs:element name="Element4"> .... </xs:element>
I plan to send our data to him by calling his WebService method. Due to the type of message generated from my system, I will have two type of messages. The first one contains Element1 and Element4 only while the second type may contains Element3, Element4 and Element1. So what are the choice does he have here?
Does he have to create two separate web services and I'll consume them accordingly?
Create one web service and I'll consume that one web service for both of my message types.
In the second opotion, does it generate any schema validation error? if so is there a way to get around it? can I send him a custom SOAP header to indicates the message type I send so he can validates it against specific xsd elements?
I'm relatively new to WebService so if I misunderstood the the basic mechanism of SOAP, XSD and WebService please feel free to point them out or correct any of my above assumptions.
I think that he could make just one webservice.
I'm not very aquainted to XSD as well, but as far as I know, there is a minOccurs property that would make this work with just one webservice. For instance:
<!--The syntax may be incorrect-->
<xsd:complexType name="yourtype">
<xsd:sequence>
<xsd:element name="Element1" minOccurs="1" maxOccurs="1" .../>
<xsd:element name="Element2" minOccurs="0" maxOccurs="1" ..../>
<xsd:element name="Element3" minOccurs="1" maxOccurs="1" ..../>
<xsd:element name="Element4" minOccurs="1" maxOccurs="1" ..../>
</xsd:sequence>
</xsd:complexType>
Look at the minOccurs="0", it means that the Element2 can be ommited by the other programmer. If you want some element to repeat 0 or N times, you can put maxOccurs="unbounded".
I'm implementing a C# web service that is supposed to accept a custom message including unbounded number of elements.
Originally, the object is defined in a XSD file like below:
<xsd:element name="LogMessage">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="1" maxOccurs="1" name="avantlog" type="tns:LogEventType">
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="LogEventType">
<xsd:sequence>
<xsd:element minOccurs="1" maxOccurs="1" name="context" type="tns:ContextType">
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ContextType">
<xsd:sequence>
<xsd:element minOccurs="1" maxOccurs="unbounded" name="severity" type="xsd:string">
</xsd:element>
</xsd:sequence>
</xsd:complexType>
And, in a CS file implementing the web service, I prepared a struct for this:
public struct logevent
{
public ContextType context;
public struct ContextType
{
public string[] severity;
}
}
However, when I tried to access an element of the 'serverity' using a line,
String temp = logevent.context.severity.GetValue(0).ToString()
, the program throws a following error:
"Index was outside the bounds of the array."
When I changed the element from 'unbounded' to '1' in the XSD file and also modified 'public string[] severity;' to 'public string severity;', it works.
Can anyone help me to make the web service to accept a message including unbounded numbers of elements?
The code that corresponds to specified XSD (if serialized using XmlSerializer) is the following:
[XmlRoot("LogMessage"]
public class LogMessage
{
[XmlElement("avantlog")]
public LogEventType AvantLog {get; set;}
}
public class LogEventType
{
[XmlArray("context")]
[XmlArrayItem("severity")]
public string[] Severity {get; set;}
}
You may have to use attributes in order to control the deserialization of the incoming XML. By default, the supported XML structure for arrays follows the form:
<Elements>
<Element>X</Element>
<Element>Y</Element>
</Element>
However, your WSDL specifies unbounded "Element" terms and does not provide for a parent "Elements" block. My understanding is that in order to use unbounded terms, you need to specify attributes to control the deserialization, as unbounded terms are not the default in .NET WSDL generation and deserialization.
This article discusses how to control deserialization using attributes:
http://msdn.microsoft.com/en-us/library/2baksw0z.aspx
You can convert your XSD to a POCO object using "XSD.exe" and then use XmlSerializer. This will make it easy to interact with multiple external systems via XML. Might want to use SGen.exe as well to increase XmlSerializer Performance. Hope this Helps
http://msdn.microsoft.com/en-us/library/x6c1kb0s(v=vs.71).aspx
http://www.jonasjohn.de/snippets/csharp/xmlserializer-example.htm