10
votes

I am using XSD's to define my DTO types in C#. I am using XSD.exe to gen the classes from the XSD's.

I have a Common.xsd that defines an Address type and I want to use this in more than one class:

  <xs:complexType name="Address">
    <xs:sequence>
      <xs:element name="Street1" type="xs:string"/>
      <xs:element name="Street2" type="xs:string"/>
      <xs:element name="City" type="xs:string"/>
      <xs:element name="State" type="xs:string"/>
      <xs:element name="Zip" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>

  <xs:element name="Address" type="mhm:Address"/>

I am referencing this in a company XSD:

  <xs:include schemaLocation=".\Common.xsd"/>
  <xs:complexType name="Company">
    <xs:sequence>
      <xs:element name="AdmCode" type="xs:string"/>
      <xs:element name="CompanyCode" type="xs:string"/>
      <xs:element name="Name" type="xs:string"/>
      <xs:element ref="mhm:Address"/>
    </xs:sequence>
  </xs:complexType>

  <xs:element name="Company" type="mhm:Company"/>

And an employee XSD:

  <xs:include schemaLocation=".\Common.xsd"/>
  <xs:complexType name="Employee">
    <xs:sequence>
      <xs:element name="EmployeeNumber" type="xs:int"/>
      <xs:element name="FirstName" type="xs:string"/>
      <xs:element name="LastName" type="xs:string"/>
      <xs:element name="Address" type="mhm:Address"/>
    </xs:sequence>
  </xs:complexType>
  <xs:element name="Employee" type="mhm:Employee"/>

I gen the classes using this command line:

xsd .\XSD\Common.xsd /c /o:. /n:"DomainModel"
xsd .\XSD\Employee.xsd /c /o:. /n:"DomainModel"
xsd .\XSD\Company.xsd /c /o:. /n:"DomainModel"

When I go to compile the project, I find that the Address type has been generated in both the Company.cs class file and the Employee.cs class file.

How can I get the Address type generated just once in the Common.cs class file and the Employee and Company types use this single Address type?

2

2 Answers

8
votes

You can use XSD.exe with multiple file arguments:

xsd .\XSD\Common.xsd .\XSD\Employee.xsd .\XSD\Company.xsd /c /o:. /n:"DomainModel"
0
votes

You basically want to split out the common types into a common assembly which is references by your other types. You have two options:

  1. Manually split them out. I know this is a generated file but if your source schemas are fairly static then it's a one off exercise.
  2. Use svcutil.exe instead. However this is much more complicated and actually you may not even be able to do this unless your schemas all abide by certain guidelines. If you are interested see below for the process.

If you fancy option 2 above then here is the general process:

  1. Extract the types from Common.xsd using the /dconly flag on svcutil. This will generate a class file with your common types.
  2. Compile this class into an assembly
  3. Extract the types from A.xsd using the /r flag and referencing your CommonTypes.dll assembly.
  4. Do the same for B.xsd

However, this approach is based on svcutil using the DataContractSerializer to do the work, as the /r flag is not available to XmlSerializer. And this will only work if the your schemas adhere to the rather strict DCS rules (can be found here: http://msdn.microsoft.com/en-us/library/ms733112.aspx).

If these rules are not adhered to then svcutil will fall back to using XmlSerializer which does not support /r flag.