I am using the .NET XSD.EXE importer to generate C# classes from a collection of XSD files. When I tried to serialize one of the classes to XML it failed (InvalidOperationException), and when I dug into it I discovered it one of the created classes appears to be wrong.
Here is the pertinent XSD code:
<xsd:complexType name="SuccessType">
<xsd:annotation>
<xsd:documentation>Indicates in a response message that a request was successfully processed.</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element ref="Warnings" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<!-- .. snip .. -->
<xsd:element name="Warnings" type="WarningsType">
<xsd:annotation>
<xsd:documentation>The processing status of a business message and any related warnings or informational messages.</xsd:documentation>
</xsd:annotation>
</xsd:element>
<!-- .. snip .. -->
<xsd:complexType name="WarningsType">
<xsd:annotation>
<xsd:documentation>A collection of warnings generated by the successful processing of a business message.</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element ref="Warning" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<!-- .. snip .. -->
<xsd:element name="Warning" type="WarningType">
<xsd:annotation>
<xsd:documentation>Defines details of a warning that occurred during message processing.</xsd:documentation>
</xsd:annotation>
</xsd:element>
<!-- .. snip .. -->
<xsd:complexType name="WarningType">
<xsd:annotation>
<xsd:documentation>Defines details of a warning that occurred during message processing.</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element ref="WarningCategory"/>
<xsd:element ref="WarningCode"/>
<xsd:element ref="WarningShortMessage"/>
<xsd:element ref="WarningMessage"/>
</xsd:sequence>
</xsd:complexType>
And here is the C# code generated from it:
public partial class SuccessType
{
private WarningType[][] warningsField;
/// <remarks/>
[System.Xml.Serialization.XmlArrayItemAttribute("Warning", typeof(WarningType), IsNullable = false)]
public WarningType[][] Warnings
{
get
{
return this.warningsField;
}
set
{
this.warningsField = value;
}
}
}
It made Warnings an array of an array of WarningType. When I attempt to serialize that to XML I get an InvalidOperationException exception:
Unable to generate a temporary class (result=1).
error CS0030: Cannot convert type 'WarningType[]' to 'WarningType'
error CS0030: Cannot convert type 'WarningType[]' to 'WarningType'
error CS0029: Cannot implicitly convert type 'WarningType' to 'WarningType[]'
error CS0029: Cannot implicitly convert type 'WarningType' to 'WarningType[]'
But if I change the generated code from WarningType[][] to WarningType[] then it serializes fine.
Short of editing the generated C# class whenever I regenerate this (which hopefully will be less frequently going forward), is there any other solution? Is this a bug in xsd.exe or is the XSD file incorrect? Maybe there is a problem in the XmlSerializer?
What I want is C# code that correctly serializes to XML that validates against the XSD. Right now the jagged array seems to be wrong because if I remove it then it generates the XML.
I am using Visual Studio 2008.
There are bugs in the xsd.exe tool. I don't remember this particular one, but I do remember finding problems with jagged arrays, and it's possible this remains a bug. if you're willing, you could use the XsdObjbectGen tool, also from Microsoft, but released independently and out-of-band from the .NET SDK.
One thing you could do is go the reverse direction: write the C# code, then generate the schema with xsd.exe, and see what is different. It's possible xsd.exe wants the schema to look a particular way, in order to correctly generate correct code for jagged arrays.
Actually, upon re-reading your question, you never said what you really wanted. Do you want SuccessType to contain an array-of-arrays, or not?
And is it WarningsType or WarningType? There's some disagreement between the code snips you provided.
Assuming you wanted the array-of-arrays, I wrote this C# code:
public class WarningType
{
public String oof;
}
public partial class SuccessType
{
private WarningType[][] warningsField;
/// <remarks/>
[System.Xml.Serialization.XmlArrayItemAttribute("Warning", typeof(WarningType[]), IsNullable = false)]
public WarningType[][] Warnings
{
get
{
return this.warningsField;
}
set
{
this.warningsField = value;
}
}
}
... then compiled it into a DLL. Then I ran xsd.exe on that DLL, and generated this XSD:
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="WarningType" nillable="true" type="WarningType" />
<xs:complexType name="WarningType">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="oof" type="xs:string" />
</xs:sequence>
</xs:complexType>
<xs:element name="SuccessType" nillable="true" type="SuccessType" />
<xs:complexType name="SuccessType">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Warnings" type="ArrayOfArrayOfWarningType" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="ArrayOfArrayOfWarningType">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="Warning" type="ArrayOfWarningType" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="ArrayOfWarningType">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="WarningType" nillable="true" type="WarningType" />
</xs:sequence>
</xs:complexType>
</xs:schema>
...and it round-trips. If I then run xsd.exe on that schema, I get a type that wraps an array-of-arrays.
Related
Is there a way to actually enforce generating FooSpecified for non-complex types like strings or integers?
The Web Service I am working with defines all record fields as nillable and minOccurs = 0
<xsd:complexType name="Constituent">
<xsd:complexContent mixed="false">
<xsd:extension base="tns:Record">
<xsd:sequence>
<xsd:element minOccurs="0" maxOccurs="1" name="ConsId" nillable="true" type="xsd:nonNegativeInteger" />
<xsd:element minOccurs="0" maxOccurs="1" name="SiteId" nillable="true" type="xsd:nonNegativeInteger" />
<xsd:element minOccurs="0" maxOccurs="1" name="PredupStatus" nillable="true" type="xsd:string" />
It also specifies Update method with Record as argument:
<xsd:element name="Update">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="0" maxOccurs="1" name="PartitionId" nillable="true" type="xsd:nonNegativeInteger" />
<xsd:element minOccurs="0" maxOccurs="1" name="Force" nillable="true" type="xsd:boolean" />
<xsd:element minOccurs="1" maxOccurs="unbounded" name="Record" type="ens:Record" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
Constituent Record has nearly 200 elements, which can be null.
At the same time, Update method on the server side is programmed to ignore all null values if there are more than 10 of them in the update request.
Reference.cs generated from the file does not contain *Specified properties for strings or integers
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.7.3062.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:object.soap.convio.com")]
public partial class Constituent : Record {
private string consIdField;
private string siteIdField;
private string predupStatusField;
private System.Nullable<AdministratorStatus> adminStatusField;
private bool adminStatusFieldSpecified;
hich causes XmlSerializer to generate lines for each field:
<q1:ConsId xsi:nil="true"/>
<q1:SiteId xsi:nil="true"/>
<q1:PredupStatus xsi:nil="true"/>
<q1:AdminStatus xsi:nil="true"/>
<q1:ConsName><q1:Title xsi:nil="true"/>
<q1:FirstName>234234</q1:FirstName>
<q1:MiddleName xsi:nil="true"/>
<q1:LastName>412341234</q1:LastName>
Which works fine until I try to blank a field out. At that point the field I am trying to blank out is being send as null and is being ignored by the server because there are more than 10 null fields in the request. To be able to remove unwanted null lines from serialization I need all fields to have *Specified property and send in the request only the field I want to be null. I can add them manually, but it's a lot of work that I need to remember to save somewhere else to avoid being removed when refreshing service reference...
Alternatively, is there a way to enforce generating ShouldSerialize property in Reference.cs?
I want to generate a proxy class (C#) from a wsdl and some xsd files. The wsdl and the xsd files are all located in the same folder on my disk.
The command I'm issuing is:
svcutil.exe AuthenticateAndGetAssertionsSOAP12v2.wsdl .xsd /t:code /l:cs /o:AuthAndGetAssertionsProxy.cs /n:,TestNamespace
but the proxy class is not generated and I get this error:
'SchemaLocation' must successfully resolve if contains any child other than -annotation-.
svcutil also states the document ID with problems is http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd.
One of the xsd files does effectively redefine a complexType defined
in this namespace like so:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<xs:redefine schemaLocation="oasis-200401-wss-wssecurity-secext-1.0.xsd">
<xs:complexType name="UsernameTokenType">
<xs:complexContent>
<xs:extension base="UsernameTokenType">
<xs:sequence>
<xs:element name="NewPassword" type="xs:base64Binary"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:redefine>
</xs:schema>
I tried fully qualifying the schemaLocation URI like this:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<xs:redefine schemaLocation="file:///C:/AuthAndGetAssertionsSOAP12v2/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<xs:complexType name="UsernameTokenType">
<xs:complexContent>
<xs:extension base="UsernameTokenType">
<xs:sequence>
<xs:element name="NewPassword" type="xs:base64Binary"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:redefine>
</xs:schema>
where C:\AuthAndGetAssertionsSOAP12v2 is the actual path to the wsdl and xsd files, but still I can't get it working.
For reference, this is how the complexType UsernameTokenType is defined in oasis-200401-wss-wssecurity-secext-1.0.xsd:
<xsd:complexType name="UsernameTokenType">
<xsd:annotation>
<xsd:documentation>This type represents a username token per Section 4.1</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="Username" type="wsse:AttributedString"/>
<xsd:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute ref="wsu:Id"/>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:complexType>
I searched a lot but I couldn't find any solution, but after reading this post
svcUtil error 'SchemaLocation' must successfully resolve if <redefine> contains any child other than <annotation>
I'm starting to think the problem may be elsewhere in the wsdl. Any suggestions?
I have a situation where we have a base class which several subclasses implement. The base class is used to force subclasses to contain certain properties that the system requires.
Anyways, I'd like to programmatically generate XSDs for the subclasses, but I would like the properties of the base class to appear in the subclass XSD, because the base class is used for internal reasons and wouldn't really have meaning to the client.
For example, currently if I have:
class Foo {
public string Id { get; set; }
}
class Bar : Foo {
public string Name { get; set; }
}
And I run that through the following code:
private string ExtractXsdFromType()
{
Type type = typeof(Bar);
XmlReflectionImporter importer = new XmlReflectionImporter();
XmlTypeMapping mapping = importer.ImportTypeMapping(type);
XmlSchemas xmlSchemas = new XmlSchemas();
XmlSchemaExporter xmlSchemaExporter = new XmlSchemaExporter(xmlSchemas);
using (var writer = new StringWriter())
{
xmlSchemaExporter.ExportTypeMapping(mapping);
xmlSchemas[0].Write(writer);
return XElement.Parse(writer.ToString()).ToString();
}
}
Then it will produce an XSD like this:
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Bar" nillable="true" type="Bar" />
<xs:complexType name="Bar">
<xs:complexContent mixed="false">
<xs:extension base="Foo">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Name" type="xs:string" />
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="Foo" abstract="true">
<xs:attribute name="Id" type="xs:int" use="required" />
</xs:complexType>
</xs:schema>
But I would like to create an XSD like this:
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Bar" nillable="true" type="Bar" />
<xs:complexType name="Bar">
<xs:complexContent mixed="false">
<xs:sequence>
<xs:attribute name="Id" type="xs:int" use="required" />
<xs:element minOccurs="0" maxOccurs="1" name="Name" type="xs:string" />
</xs:sequence>
</xs:complexContent>
</xs:complexType>
</xs:schema>
Does anyone know if this is possible?
I would be extremely surprised to actually see this possible the way you described simply because to do it like so would break things from an Object Orientation perspective, at least most of the time. For example, if a class uses a property of a type, then in OO any class extending that type would be allowed instead.
Collapsing the class hierarchy (which is what you describe if I understood correctly), would make it impossible to correctly create an XSD model. There would be limitations even when trying to do so from an XSD refactoring perspective, particularly where abstract types get involved, or substitution groups (I am talking in general).
I have the following in a WSDL I am consuming;
<xsd:complexType name="SomeClassType">
<xsd:sequence>
<xsd:element type="xsd:string" name="errorMessage" minOccurs="1" nillable="true" maxOccurs="1"> </xsd:element>
<xsd:element type="tp:ArrayOfArrayOfString" name="values" minOccurs="1" nillable="true" maxOccurs="1"> </xsd:element>
<xsd:element type="xsd:boolean" name="isEmpty" minOccurs="1" maxOccurs="1"> </xsd:element>
</xsd:sequence>
</xsd:complexType>
where
<xsd:complexType name="ArrayOfArrayOfString">
<xsd:complexContent>
<xsd:restriction base="soapenc:Array">
<xsd:attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[,]"></xsd:attribute>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
However using wsdl.exe from MS (Runtime Version: 1.1.4322.573) generates
public class SomeClassType {
///
public string errorMessage;
///
public string[] values;
///
public bool isEmpty;
}
I expected string[,] values not string[] values
Is there a fix or a work around to this problem? (other than manually changing the generated code)
I had to set the type="tp:ArrayOfArrayOfString" to type="tp:ArrayOfString" and the maxOccurs="unbounded"
I believe you could try the WCF proxy generator (I believe WCF uses some other util, not wsdl.exe) - maybe that would be useful, but if that fails - I think that manually editing the generated code is your only option.
Try svcutil.exe. it is advisable to try a newer version of .net.
I've been searching for an answer for quite some time without any luck.
I'm using NDbUnit for my test data and I want to be able to generate my XSD files automatically. I don't want to have to regenerate my XSD files each time I add a new property to my classes. So my plan is to automatically generate the XSD files using the XsdDataContractExporter class since some of my classes contain IList and I got some errors using the xml serializer.
this is the code I got so far:
XsdDataContractExporter exporter = new XsdDataContractExporter();
exporter.Export(typeof(Supplier));
//XmlQualifiedName xmlQualifiedName = exporter.GetRootElementName(typeof(Supplier));
foreach (XmlSchema schema in exporter.Schemas.Schemas()) {
XmlWriter writer = XmlWriter.Create(String.Format(#"..\..\data\{0}.xsd", GetSchemaName(schema)), new XmlWriterSettings() {
ConformanceLevel = ConformanceLevel.Auto,
Encoding = Encoding.UTF8,
Indent = true,
OmitXmlDeclaration = false
});
foreach (XmlSchemaObject include in schema.Includes) {
XmlSchemaImport importedSchema = include as XmlSchemaImport;
if (importedSchema != null) {
ArrayList lst = new ArrayList(exporter.Schemas.Schemas(importedSchema.Namespace));
XmlSchema actualImportedSchema = (XmlSchema)lst[0];
importedSchema.Schema = actualImportedSchema;
importedSchema.SchemaLocation = Path.GetFullPath(String.Format(#"..\..\data\{0}.xsd", GetSchemaName(actualImportedSchema)));
}
}
schema.Write(writer);
writer.Close();
}
DataSet ds = new DataSet();
ds.ReadXmlSchema(#"..\..\data\business.model.supplier.xsd");
the problem is that I get an error when reading the schema which is:
failed: System.InvalidOperationException : Nested table 'SupplierCategory' which inherits its namespace cannot have multiple parent tables in different namespaces.
The bottom line is, I want to use a dynamically generated XSD file from a type to use with NDBUnit to populate my database with test data. Is this the right approach ? This is the schema that are generated and that gives my the error:
Supplier:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:tns="http://schemas.datacontract.org/2004/07/Business.Model.Supplier" elementFormDefault="qualified" targetNamespace="http://schemas.datacontract.org/2004/07/Business.Model.Supplier" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import schemaLocation="C:\dev\skeleton\branches\dev\src\testconsole\data\business.model.supplier.category.xsd" namespace="http://schemas.datacontract.org/2004/07/Business.Model.Supplier.Category" />
<xs:import schemaLocation="C:\dev\skeleton\branches\dev\src\testconsole\data\arrays.xsd" namespace="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
<xs:complexType name="Supplier">
<xs:sequence>
<xs:element minOccurs="0" name="Categories" nillable="true" xmlns:q1="http://schemas.datacontract.org/2004/07/Business.Model.Supplier.Category" type="q1:ArrayOfSupplierCategory" />
<xs:element minOccurs="0" name="Comments" nillable="true" xmlns:q2="http://schemas.microsoft.com/2003/10/Serialization/Arrays" type="q2:ArrayOfstring" />
<xs:element minOccurs="0" name="Description" nillable="true" type="xs:string" />
<xs:element minOccurs="0" name="Name" nillable="true" type="xs:string" />
</xs:sequence>
</xs:complexType>
<xs:element name="Supplier" nillable="true" type="tns:Supplier" />
</xs:schema>
SupplierCategory:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:tns="http://schemas.datacontract.org/2004/07/Business.Model.Supplier.Category" elementFormDefault="qualified" targetNamespace="http://schemas.datacontract.org/2004/07/Business.Model.Supplier.Category" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="ArrayOfSupplierCategory">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="SupplierCategory" nillable="true" type="tns:SupplierCategory" />
</xs:sequence>
</xs:complexType>
<xs:element name="ArrayOfSupplierCategory" nillable="true" type="tns:ArrayOfSupplierCategory" />
<xs:complexType name="SupplierCategory">
<xs:sequence>
<xs:element minOccurs="0" name="Description" nillable="true" type="xs:string" />
</xs:sequence>
</xs:complexType>
<xs:element name="SupplierCategory" nillable="true" type="tns:SupplierCategory" />
</xs:schema>
Any advice would be great !
Thx,
Franck
See the list of suggestions in this post Getting XML Schema from MS SQL Database (specifically the top-voted answer) but also note my suggestion of using MyGeneration to achieve the same thing.
That's a problem I've also been facing quite a time later, as we were using NDbUnit for integration tests in our project – ended up with a custom library, which doesn't need a schema to be defined separately, it reads it from database on its own. Library is Reseed.