I am generating a datacontract with svcutil from a webservice.
svcutil /language:cs /noConfig /targetclientversion:Version35
/out:Generated\ProductService.cs http://example.com/ProductService.svc?wsdl
The fields generated looks like this:
private System.Nullable<System.DateTime> createdField;
private bool createdFieldSpecified;
How can the fields be both nullable and have a specified field?
it depends on the source Wsdl. I bet there is something this (not sure of the syntax):
<xsd:element name="created" type="xsd:datetime" minOccurs="0" xsd:nil="true" />
svcutil.exe use nillable to produce a Nullable<> field, and minOccurs to produce a field + specified combination.
I also bet the WSDL is not a .Net generated WSDL !
The class generation is driven by XSD schema of the web service.
In order to generate nullable fields. The field should be marked as nillable.
<xs:element minOccurs="0" maxOccurs="1" name="created" type="xs:dateTime" nillable="true" />
The XML will look like this.
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<created xsi:nil="true" />
</root>
I believe that this field in your schema looks like this:
<xs:element minOccurs="0" maxOccurs="1" name="created" />
and it would omit the element completely if createdFieldSpecified = false:
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
</root>
The bottom line: web service schema should be updated in order to generate nullable fields with svcutil.
Related
I want to call an external SOAP service which i want to generate proxy classes for. The .wsdl is not exposed online, but provided alongside a set .xsd files. I'm then using svcutil (also tried with dotnet-svcutil 1.0.4) to generate the classes. Consider the following XML:
<xs:complexType name = "ValidationReply" abstract="false">
<xs:complexContent>
<xs:extension base="common:Reply">
<xs:sequence>
<xs:element name="data" type="ns:ValidationReplyData" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="ValidationReplyData" abstract="false">
<xs:sequence>
<xs:element name="errors" type="ns:Error" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
Generates the following code:
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("dotnet-svcutil", "1.0.4")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="Namespace")]
public partial class ValidationReply: Reply
{
private Error[] dataField;
/// <remarks/>
[System.Xml.Serialization.XmlArrayAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, Order=0)]
[System.Xml.Serialization.XmlArrayItemAttribute("errors", Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)]
public Error[] data
{
get
{
return this.dataField;
}
set
{
this.dataField = value;
}
}
}
The issue is that the XML defines an inner type containing the list of errors, where Svcutil puts the list of errors directly as the data field, instead making the data field of type ValidationReplyData. The ValidationReplyData is not generated at all.
The code compiles without any issues and i am able to call the external service without errors. The data field is however always null as the response is on the format:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<fl:ValidationReply xmlns:fw="Namespace" >
<data>
<errors>
<code>236</code>
</errors>
<errors>
<code>237</code>
</errors>
</data>
</fl:ValidationReply>
</S:Body>
</S:Envelope>
Which does not deserialize correctly to the generated class.
In short, does anyone know how to force Svcutil to generate all classes? Redundant or not.
I have simplified the xml snippets, so there may be some inconsistencies in the example, but the digest of the problem is the missing ValidationReplyData class-
In our project we are using Xsd2Code to generate c# code.
The XSD I am trying to adjust looks like this:
<?xml version="1.0"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="File">
<xs:complexType>
<xs:sequence>
<xs:element name="Version" type="xs:string" />
<xs:element name="Language" type="xs:string" />
<xs:element name="Component" type="xs:anyType" minOccurs="1" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Within our project we now defined an abstract class Version. Is it possible to use our own class Version instead of string as the type of the element Version within the Xsd?
We would like to generate as many classes as possible using Xsd2Code. That's why I want to avoid to also having to create the File class by hand.
Thanks in advance for any help.
You can create a new abstract class Version in xsd scheme and then make your defined Version class as partial and put it to the same namespace as the generated classes. By default all your generated classes must be partial.
I am trying to create a waypoint generator using windows forms, that allows a user to create waypoint & path data via a GUI & output the data to an XML file. I've chosen to take advantage of the built in c# XML serialization feature, but have been unable to format the XML output in the way required by the client.
A stripped version of the waypoint data object would look something like the following:
// Waypoint data class
[XmlRoot("RootNode")]
public class WaypointProjectData
{
[XmlElement("Map")] // Also tried to use XmlElementAttribute,
[XmlAttribute("file")] // XmlAttributeAttribute, and many variations
// of these qualifiers, with no success
public string m_szMapImageFileName;
[XmlAttribute("width")]
public int m_iWidth;
[XmlAttribute("height")]
public int m_iHeight;
[XmlArray("Nodes")]
public ArrayList m_aoNodes;
WaypointProjectData()
{
m_szMapImageFileName = "map.png";
m_aoNodes = new ArrayList();
}
}
The client requires that the XML output conforms with the following layout/format:
<RootNode>
<Map file="map.png" width="100" height="100" />
<OtherData var="variable" data="10" />
<Nodes>
<Node x="10" y="30" />
<Node x="30" y="20" /> // etc...
</Nodes>
</RootNode>
Some clear examples on how to do this using c# xml serialization would be very helpful. Thanks!
When I have to serialize something in a specific Xml format like this, I start with a schema (inferred if necessary, hand-crafted if known). Then I use the VS xsd tool to create the serialization classes (and yes, I know xsd can be used for the inferring schema part—I just never bother with it for that purpose).
So if you have an xsd file like this one created from your example (note that I specified data types as much as possible—this helps the xsd tool to use the appropriate types for properties):
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="RootNode">
<xs:complexType>
<xs:sequence>
<xs:element name="Map">
<xs:complexType>
<xs:attribute name="file" type="xs:string"/>
<xs:attribute name="width" type="xs:decimal"/>
<xs:attribute name="height" type="xs:decimal"/>
</xs:complexType>
</xs:element>
<xs:element name="OtherData">
<xs:complexType>
<xs:attribute name="var" type="xs:string"/>
<xs:attribute name="data" type="xs:decimal"/>
</xs:complexType>
</xs:element>
<xs:element name="Nodes" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="Node" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="x" type="xs:decimal"/>
<xs:attribute name="y" type="xs:decimal"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
If you name this Root.xsd, then you can go to the VS command line and run
xsd Root.xsd /c /n:myProject.Xml
That'll create a class file (named Root.cs because that's the default when processing Root.xsd) that contains objects you can easily plug into .Net to serialize and deserialize the XML. Note that I specified the namespace the classes will have ("/n:myProject.Xml"). I prefer to control that namespace, but defaults are usually fine for the rest. Further, the tool creates partial classes, so if you want custom property accessors, you're fine to add them in a separate file that won't get creamed if you need to run the tool again.
Another tip, I create a text file in my project with the name "<xsd name> xsd Command Line.txt". That way I just have to paste that into the VS command line and don't have to remember everything else I used.
As soon as you go off the beaten track serialisation is a huge PIA.
You need something to mark up as map, probably OtherData as well, so that means you need a class or struct that corresponds to the node.
e.g. WaypointProejctdata as a class Map, that has properties filename, width and height.
My general rule of thumb, is as soon as I have to start messing with my objects to get the xml, serialisation gets binned,and I add an interface that takes an XmlReader or Writer and implement it.
Tryng to get serialisation to do what you want is usually way more code and far less comprehensible than doing that.
I have created a C# .net 2.0 webservice. I need to capture the raw XML sent from the client and validate it against an XSD and return any errors to the client. The webservice will allow the client to upload a list of widgets to our system.
The following is some background info:
I created an XSD to model a "Widget", which is a complex object. It looks something like this:
<xs:element name="WidgetList">
<xs:complexType>
<xs:sequence>
<xs:element name="Widget" maxOccurs="unbounded" type="WidgetType" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="WidgetType">
<xs:sequence maxOccurs="1" minOccurs="1">
<xs:element name="Seller" type="AccountType" maxOccurs="1" minOccurs="1" />
<xs:element name="Buyer" type="AccountType" maxOccurs="1" minOccurs="1" />
</xs:sequence>
<xs:attribute name="Market" type="MarketType" use="required" />
</xs:complexType>
<!-- etc... -->
Then, I used XSD.exe to generate classes from the xsd.
The Classes that are created are WidgetList, Widget, Seller, Buyer, etc.
Next, I created a webservice method to take the Upload. It looks like so:
[WebMethod]
[SoapHeader("SecurityAuthenticationHeader", Direction = SoapHeaderDirection.In)]
public string UploadWidgets(WidgetList wl)
{
//Need to validate the XML against the XSD here.
//Code to import...
}
Two questions:
Is there a way that I can validate the raw XML sent from the client against my original XSD?
Is there anything wrong with the way I have created this service?
UPDATE:
The reason I need to do this is that even though the XSD says fields are required or minOccurs=1, it seems that those properties are not required in the WSDL (Not really sure why).
This is what part of the WSDL looks like (removed unnecessary parts for brevity):
<s:schema elementFormDefault="qualified" targetNamespace="http://www.clearpar.com/XMLSchema">
<s:element name="lt">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="unbounded" name="LoanTrade" type="s1:LoanTradeType" />
</s:sequence>
</s:complexType>
</s:element>
<s:complexType name="LoanTradeType">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="Seller" type="s1:AccountType" />
<s:element minOccurs="0" maxOccurs="1" name="Buyer" type="s1:AccountType" />
</s:sequence>
<s:attribute name="Market" type="s1:MarketType" use="required" />
</s:complexType>
<s:complexType name="AccountType">
<s:attribute name="Name" type="s:string" />
<s:attribute name="ClientSystemID" type="s:string" />
</s:complexType>
I don't think that there's a simple way to do this.
There is an MSDN article on implementing a SoapExtension to perform schema validation. This is the route I took, with a few enhancements.
It's unfortunate that there is no automatic mechanism to validate against the WSDL, especially since the service inherently knows the schema already. I would be interested to know if this situation has changed in WCF: I'm porting my services now and would love it if they've solved this problem more elegantly.
Since you need more strict control over your WSDL, I recommend writing it manually, and generate both your service contract interface/data/messages and client proxies from a single WSDL contract. There is a great project on CodePlex, WCSF.blue, that can help you do contract-first service development.
For question 1: the only way that I know to validate the incoming message is to create SOAP Extension that validates the incoming message against the expected schema. The reason is that the .NET plumbing deserializes the incoming XML into an object before entering your WebMethod. If there is an issue with the incoming XML then your Web Method will never be entered and a SOAP Fault will be returned to the client. Another issue is that perhaps the deserializer does not deserialize "properly". Read the XML Schema Validation article for more information.
In terms of question 2: your approach is correct for contract first development using (asmx) web services. My question back to you is why not use WCF to expose a web service instead of the older ASMX technology. WCF supports schema validation as well.
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.