Customize Data Types Generation

Topics: General Discussion Forum, Service Factory Modeling Edition Forum
Mar 11, 2009 at 9:48 AM
Edited Mar 11, 2009 at 12:10 PM
Hello all,

How create costumized datatype from an XSD Schema. I want extend some property generated and insert some new functionality.


Project Details:
Model with ASMX technology and xsd messages .

Thanks,

Steve
Developer
Mar 11, 2009 at 10:49 PM
Can you be more specific? If you want to change the code generated, you may simply update the text template files "DataContract.tt" in the DataContract DSL project.
Otherwise you may go and create a partial class (same as the Data Contract that you want to extend) and add the extra functionality.
You can find samples of this in the Extensibility Hands-on labs (home page).
Mar 12, 2009 at 8:24 AM

Thanks for quick response,

my project include ASMX implementation based on XSD,

 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="***" targetNamespace="***" elementFormDefault="qualified" attributeFormDefault="unqualified">
 <xs:element name="DoctorDetailsRequest">
  <xs:complexType>
   <xs:sequence>
    <xs:element name="MessageInfo" type="DoctorDetails.MessageInfo"/>
    <xs:element name="Parameters" type="DoctorDetails.Parameters"/>
   </xs:sequence>
  </xs:complexType>
 </xs:element>
 <xs:complexType name="DoctorDetails.MessageInfo">
  <xs:sequence>
..............
  </xs:sequence>
 </xs:complexType>
 <xs:complexType name="DoctorDetails.Parameters">
  <xs:sequence>
   <xs:element name="DoctorID" type="xs:long" nillable="true" minOccurs="0"/>
   <xs:element name="DoctorLicenseNo" type="xs:int" nillable="true" minOccurs="0"/>
  </xs:sequence>
 </xs:complexType>
</xs:schema>

I created Model with xsd messages
when it generate data types from response part I get class in DataTypes project like this:
namespace ASMXService1.DataTypes {
    /// <remarks/>
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "2.0.50727.3053")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlTypeAttribute(TypeName="DoctorDetails.Parameters", Namespace="****")]
    public partial class DoctorDetailsParameters {
        private System.Nullable<long> doctorIDField;
        private bool doctorIDFieldSpecified;
        private System.Nullable<int> doctorLicenseNoField;
        private bool doctorLicenseNoFieldSpecified;
        
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
        public System.Nullable<long> DoctorID {
            get {
                return this.doctorIDField;
            }
            set {
                this.doctorIDField = value;
            }
        }
       
        /// <remarks/>
        [System.Xml.Serialization.XmlIgnoreAttribute()]
        public bool DoctorIDSpecified {
            get {
                return this.doctorIDFieldSpecified;
            }
            set {
                this.doctorIDFieldSpecified = value;
            }
        }
       
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
        public System.Nullable<int> DoctorLicenseNo {
            get {
                return this.doctorLicenseNoField;
            }
            set {
                this.doctorLicenseNoField = value;
            }
        }
       
        /// <remarks/>
        [System.Xml.Serialization.XmlIgnoreAttribute()]
        public bool DoctorLicenseNoSpecified {
            get {
                return this.doctorLicenseNoFieldSpecified;
            }
            set {
                this.doctorLicenseNoFieldSpecified = value;
            }
        }
    }
}

I need make some changes for the generated  properties for example:

        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
        public System.Nullable<int> DoctorID{
            get {
                return this.DoctorIDField;
            }
            set {
                this.DoctorIDField = value;
--->          this.DoctorIDSpecified = true; // inserted statement
            }
        }

Using a partial class for this change,  not in option . I am checked DataContract.tt, but I don't think it participated in this code generation



Thanks,

Steve

Developer
Mar 12, 2009 at 2:43 PM
Edited Mar 12, 2009 at 3:49 PM
You are right regarding the text template because this code is being generated by the XsdElement generator that creates the code from the schema and not from a text template.
However, you can have full control of code gen from xsd if you write a code generation strategy that inherits from the built in "XmlSchemaCodeGenerationStrategy" and overwrite the method "UpdateUnit".
The good thing about this, is that you can control all the generated code from the CodeCompileUnit passed as the "unit" parameter. There you can add that line to any property.
In order to replace the built-in strategy with yours, you need to update the file "\WssfSrc\Extenders\ServiceFactory.Extenders.ServiceContract.Asmx\Source\CodeGeneration\AsmxXsdMessageElementLink.cs" and change:

[
CodeGenerationStrategy(typeof(XmlSchemaCodeGenerationStrategy))]
with:
[CodeGenerationStrategy(typeof(YourCustomXmlSchemaCodeGenerationStrategy))] 

In summary you need to create a new strategy that derives from "XmlSchemaCodeGenerationStrategy" like:

// add the using statement: using System.CodeDom;

public class YourCustomXmlSchemaCodeGenerationStrategy : XmlSchemaCodeGenerationStrategy
{
    protected override void UpdateUnit(CodeCompileUnit unit, string currentTypeName, IArtifactLink link)
    {
        // Here you may need to locate your type, so traversing unit is the way to go
        foreach (CodeNamespace ns in unit.Namespaces)
        {
            foreach (CodeTypeDeclaration codeType in ns.Types)
            {
                if (codeType.Name == "DoctorDetailsParameters")
                {
                    // now look your property
                    foreach (CodeMemberProperty property in codeType.Members)
                    {
                        if (property.Name == "DoctorID")
                        {
                            // this is your property so add your extra statement
                            property.SetStatements.Add(...);
                            // when done, just return
                            return;
                        }
                    }
                }
            }
        }
    }
 }

In order to do this, you should use the source version so you can change the AsmxXsdMessageElementLink.cs file mentioned above.

Regards,
Hernan
Developer
Mar 12, 2009 at 3:07 PM
Another option, where you can use the binary version of WSSF and much simpler where you can use a partial class, is to simply set this value from your service implementation class while you create an instance of your DC class like this:

DoctorDetailsParameters  myParams = new DoctorDetailsParameters();
myParams.DoctorIDSpecified = myParams.DoctorID != null;
Mar 12, 2009 at 3:40 PM

Thanks to  all.

I think the option with "XmlSchemaCodeGenerationStrategy" better for my case, because the xsd include a lot of values.