Last topic explained how the instances of many types in the .NET Framework can be passed in the CSO Gateway. This topic deals with types you have defined yourself, types for which you can modified the source code.

In one word, you must make your types cso-ready.

The steps required to acheive this varies depending on whether it is a class, a struct, an interface or an enum. To illustrate these different cases, example #10 in topic Learn by examples will be re-built step by step.

This topic contains the following sections.

Classes

Making one of your class cso-ready can be very easy or very difficult. Small, standalone entity-like classes will be made cso-ready with almost no intervention from you. For more complex classes a number of workarounds can be used. The following paragraphs explains how to make a class cso-ready.

This section contains the following subsections.

Decorate the class with the CsoGeneratedTypeAttribute code attribute

To be considered cso-ready, a class must be decorated with the CsoGeneratedTypeAttribute code attribute. This code attribute also exposes a few parameters that gives you some control over how the cso-generated class will be created.

CopyCsoGeneratedTypeAttribute usage
[CsoGeneratedType]
public class CustomerInfo
{
    ...
}

Verify that all of the properties return type are or will be cso-compatible types.

To create a cso-generated class, the Type Morpher will lookup all the public properties of the class including inherited ones and create a cso-generated class based on these. The constructor will have a number of parameters equivalent to the number of public properties and the name of the parameters will be the same as the name of the properties. Also, for each property X in the class, the cso-generated class will have two accessors methods get_X and set_X.

When the Object Gateway will convert an instance of that class, it will call each of these properties to retreive the value and convert it. This implies that the return type of all public properties must be cso-compatible (or cso-ready). The following class has only 3 properties all with return types handled directly by the CSO Gateway (System.String and System.DateTime). Is this case, there is nothing to do apart from decorating the class with the CsoGeneratedTypeAttribute:

CopyClass CustomerInfo
[CsoGeneratedType]
public class CustomerInfo
{
    private string firstName;
    public string FirstName
    {
        get { return firstName; }
    }

    private string lastName;
    public string LastName
    {
        get { return lastName; }
    }

    private DateTime dateOfBirth;
    public DateTime DateOfBirth
    {
        get { return dob; }
    }

    public CustomerInfo(string fn, string ln, DateTime dob)
    {
        firstName = fn;
        lastName = ln;
        dateOfBirth = dob;
    }
}
CopyCso-generated class for class CustomerInfo
// ****************************************
// CSO Gateway version 0.7.1.0
// Copyright (C) 2010 Pascal Dufresne
// http://csogateway.codeplex.com
// http://csogateway.metaobjects.ca
// ****************************************
// class DefaultNamespace.CustomerInfo
// dynamically generated from class: "CustomerInfo, App_Web_szkykeht, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
// ****************************************


Type.registerNamespace('DefaultNamespace');

DefaultNamespace.CustomerInfo = function DefaultNamespace$CustomerInfo(FirstName, LastName, DateOfBirth)
{
  this._FirstName = FirstName;
  this._LastName = LastName;
  this._DateOfBirth = DateOfBirth;
}

// FirstName property
DefaultNamespace.CustomerInfo.prototype.get_FirstName = function DefaultNamespace$CustomerInfo$get_FirstName()
{
  return this._FirstName;
}
DefaultNamespace.CustomerInfo.prototype.set_FirstName = function DefaultNamespace$CustomerInfo$set_FirstName(value)
{
  this._FirstName = value;
}

// LastName property
DefaultNamespace.CustomerInfo.prototype.get_LastName = function DefaultNamespace$CustomerInfo$get_LastName()
{
  return this._LastName;
}
DefaultNamespace.CustomerInfo.prototype.set_LastName = function DefaultNamespace$CustomerInfo$set_LastName(value)
{
  this._LastName = value;
}

// DateOfBirth property
DefaultNamespace.CustomerInfo.prototype.get_DateOfBirth = function DefaultNamespace$CustomerInfo$get_DateOfBirth()
{
  return this._DateOfBirth;
}
DefaultNamespace.CustomerInfo.prototype.set_DateOfBirth = function DefaultNamespace$CustomerInfo$set_DateOfBirth(value)
{
  this._DateOfBirth = value;
}

DefaultNamespace.CustomerInfo.registerClass('DefaultNamespace.CustomerInfo', CsoGateway.System.CsoGenerated, Sys.IDisposable);
CopyValue-creation-script for Guy Lafleur, born February 2nd 1954
<script type="text/javascript">var aCustomerInfo = new DefaultNamespace.CustomerInfo('Guy','Lafleur',new Date(-500238000000));</script>

Now, suppose you add a field/property of type System.Data..::.DataTable.

CopyNew property of type System.Data.DataTable
private DataTable transactions;
public DataTable Transactions
{
    get { return transactions; }
}
This type is not cso-compatible and it cannot be made cso-ready. So now the CustomerInfo class is no longer cso-ready. Trying the view the page will cause an exception with a message similar to this:
[EXC-TM-002] Class: CustomerInfo, Property: get_Transactions, Return type: System.Data.DataTable. The return type is not cso-compatible.

If this data is not really needed on the client-side, the simplest solution is to exclude the property with the ca.metaobjects.csogateway..::.CsoPropertyExcludeAttribute code attribute:

CopyExcluding property of type System.Data.DataTable
private DataTable transactions;
[CsoPropertyExclude]
public DataTable Transactions
{
    get { return transactions; }
}
Here the Type Morpher will ignore the Transactions property and the cso-generated class will be identical to the one shown above.

Now let's add a field/property HomeTimeZone of type System..::.TimeZone. This type too is not cso-compatible. Let's say that in this case, after some analysis, you realize that the only piece of information needed is the value of the TimeZone..::.StandardName property. Here, a quick workaround is to exclude the HomeTimeZone property and defined another property called HomeTimeZoneName that returns the StandardName. Since the new property's return type is System.String, the CustomerInfo class is cso-ready again.

CopyWorkaround for non-cso-compatible property of type System.TimeZone
private TimeZone homeTimeZone;
[CsoPropertyExclude]
public TimeZone HomeTimeZone
{
    get { return homeTimeZone; }
}

public string HomeTimeZoneName
{
    get { return homeTimeZone.StandardName; }
}
The value-creation-script for an object of type CustomerInfo now looks like that:
CopyValue-creation-script for an instance of CustomerInfo
<script type="text/javascript">var aCustomerInfo = new DefaultNamespace.CustomerInfo('Guy','Lafleur',new Date(-500238000000),'Eastern Standard Time');</script>

We will now create a base class for the CustomerInfo class. The base class is PersonInfo, it is abstract and we will move the following field/property in it: FirstName, LastName, DateOfBirth, HomeTimeZone. We will also create the constant field MAX_NAME_LENGTH to demonstrate what the Type Morpher does with constant fields whose types are cso-compatible. The classes PersonInfo and CustomerInfo and the cso-generated class CustomerInfo will now look like this:

CopyCustomerInfo and PersonInfo classes
public abstract class PersonInfo
{
    private const string NAME_MAX_LENGTH = 32;

    private string firstName;
    public string FirstName
    {
        get { return firstName; }
    }

    private string lastName;
    public string LastName
    {
        get { return lastName; }
    }

    private DateTime dateOfBirth;
    public DateTime DateOfBirth
    {
        get { return dateOfBirth; }
    }

    private TimeZone homeTimeZone;
    [CsoPropertyExclude]
    public TimeZone HomeTimeZone
    {
        get { return homeTimeZone; }
    }

    public string HomeTimeZoneName
    {
        get { return homeTimeZone.StandardName; }
    }

    public PersonInfo(string fn, string ln, DateTime dob, TimeZone tzr)
    {
        firstName = fn;
        lastName = ln;
        dateOfBirth = dob;
        homeTimeZone = tzr;
    }
}

[CsoGeneratedType]
public class CustomerInfo : PersonInfo
{
    private DataTable transactions;
    [CsoPropertyExclude]
    public DataTable Transactions
    {
        get { return transactions; }
    }

    public CustomerInfo(string fn, string ln, DateTime dob, DataTable transacs, TimeZone tzr)
        : base(fn, ln, dob, tzr)
    {
        transactions = transacs;
    }
}
CopyCustomerInfo cso-generated class
// ****************************************
// CSO Gateway version 0.7.1.0
// Copyright (C) 2010 Pascal Dufresne
// http://csogateway.codeplex.com
// http://csogateway.metaobjects.ca
// ****************************************
// class DefaultNamespace.CustomerInfo
// dynamically generated from class: "CustomerInfo, App_Web_lsubz6er, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
// ****************************************


Type.registerNamespace('DefaultNamespace');

DefaultNamespace.CustomerInfo = function DefaultNamespace$CustomerInfo(HomeTimeZoneName, FirstName, LastName, DateOfBirth)
{
  this._HomeTimeZoneName = HomeTimeZoneName;
  this._FirstName = FirstName;
  this._LastName = LastName;
  this._DateOfBirth = DateOfBirth;
}

DefaultNamespace.PersonInfo.NAME_MAX_LENGTH = 32;

// HomeTimeZoneName property
DefaultNamespace.CustomerInfo.prototype.get_HomeTimeZoneName = function DefaultNamespace$CustomerInfo$get_HomeTimeZoneName()
{
  return this._HomeTimeZoneName;
}
DefaultNamespace.CustomerInfo.prototype.set_HomeTimeZoneName = function DefaultNamespace$CustomerInfo$set_HomeTimeZoneName(value)
{
  this._HomeTimeZoneName = value;
}

// FirstName property
DefaultNamespace.CustomerInfo.prototype.get_FirstName = function DefaultNamespace$CustomerInfo$get_FirstName()
{
  return this._FirstName;
}
DefaultNamespace.CustomerInfo.prototype.set_FirstName = function DefaultNamespace$CustomerInfo$set_FirstName(value)
{
  this._FirstName = value;
}

// LastName property
DefaultNamespace.CustomerInfo.prototype.get_LastName = function DefaultNamespace$CustomerInfo$get_LastName()
{
  return this._LastName;
}
DefaultNamespace.CustomerInfo.prototype.set_LastName = function DefaultNamespace$CustomerInfo$set_LastName(value)
{
  this._LastName = value;
}

// DateOfBirth property
DefaultNamespace.CustomerInfo.prototype.get_DateOfBirth = function DefaultNamespace$CustomerInfo$get_DateOfBirth()
{
  return this._DateOfBirth;
}
DefaultNamespace.CustomerInfo.prototype.set_DateOfBirth = function DefaultNamespace$CustomerInfo$set_DateOfBirth(value)
{
  this._DateOfBirth = value;
}

DefaultNamespace.CustomerInfo.registerClass('DefaultNamespace.CustomerInfo', CsoGateway.System.CsoGenerated, Sys.IDisposable);
You will notice that little has changed in the cso-generated class. This is because PersonInfo is not cso-ready and so, no cso-generated class has been create for it. The properties defined in the PersonInfo class however are inherited by the CustomerInfo class and must be defined for it in the cso-generated class. In this situation, the Type Morpher will simply put the definition of those inherited properties in the CustomerInfo cso-generated class. The only thing that has changed is the order of the parameters in the constructor, because parameters corresponding to base class properties are always at the end.

Now let's make the PersonInfo class cso-ready and see what happens to the cso-generated classes.

CopyCustomerInfo and PersonInfo classes
[CsoGeneratedType]
public abstract class PersonInfo
{
    private const string NAME_MAX_LENGTH = 32;    

    private string firstName;
    public string FirstName
    {
        get { return firstName; }
    }

    private string lastName;
    public string LastName
    {
        get { return lastName; }
    }

    private DateTime dateOfBirth;
    public DateTime DateOfBirth
    {
        get { return dateOfBirth; }
    }

    private TimeZone homeTimeZone;
    [CsoPropertyExclude]
    public TimeZone HomeTimeZone
    {
        get { return homeTimeZone; }
    }

    public PersonInfo(string fn, string ln, DateTime dob, TimeZone tzr)
    {
        firstName = fn;
        lastName = ln;
        dateOfBirth = dob;
        homeTimeZone = tzr;
    }
}

[CsoGeneratedType]
public class CustomerInfo : PersonInfo
{
    private DataTable transactions;
    [CsoPropertyExclude]
    public DataTable Transactions
    {
        get { return transactions; }
    }

    public string HomeTimeZoneName
    {
        get { return HomeTimeZone.StandardName; }
    }

    public CustomerInfo(string fn, string ln, DateTime dob, DataTable transacs, TimeZone tzr)
        : base(fn, ln, dob, tzr)
    {
        transactions = transacs;
    }
}
CopyPersonInfo cso-generated class
// ****************************************
// CSO Gateway version 0.7.1.0
// Copyright (C) 2010 Pascal Dufresne
// http://csogateway.codeplex.com
// http://csogateway.metaobjects.ca
// ****************************************
// class DefaultNamespace.PersonInfo
// dynamically generated from class: "PersonInfo, App_Web_x0jpr5ez, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
// ****************************************


Type.registerNamespace('DefaultNamespace');

DefaultNamespace.PersonInfo = function DefaultNamespace$PersonInfo(FirstName, LastName, DateOfBirth)
{
  this._FirstName = FirstName;
  this._LastName = LastName;
  this._DateOfBirth = DateOfBirth;
}

DefaultNamespace.PersonInfo.NAME_MAX_LENGTH = 32;

// FirstName property
DefaultNamespace.PersonInfo.prototype.get_FirstName = function DefaultNamespace$PersonInfo$get_FirstName()
{
  return this._FirstName;
}
DefaultNamespace.PersonInfo.prototype.set_FirstName = function DefaultNamespace$PersonInfo$set_FirstName(value)
{
  this._FirstName = value;
}

// LastName property
DefaultNamespace.PersonInfo.prototype.get_LastName = function DefaultNamespace$PersonInfo$get_LastName()
{
  return this._LastName;
}
DefaultNamespace.PersonInfo.prototype.set_LastName = function DefaultNamespace$PersonInfo$set_LastName(value)
{
  this._LastName = value;
}

// DateOfBirth property
DefaultNamespace.PersonInfo.prototype.get_DateOfBirth = function DefaultNamespace$PersonInfo$get_DateOfBirth()
{
  return this._DateOfBirth;
}
DefaultNamespace.PersonInfo.prototype.set_DateOfBirth = function DefaultNamespace$PersonInfo$set_DateOfBirth(value)
{
  this._DateOfBirth = value;
}

DefaultNamespace.PersonInfo.registerClass('DefaultNamespace.PersonInfo', CsoGateway.System.CsoGenerated, Sys.IDisposable);
CopyCustomerInfo cso-generated class
// ****************************************
// CSO Gateway version 0.7.1.0
// Copyright (C) 2010 Pascal Dufresne
// http://csogateway.codeplex.com
// http://csogateway.metaobjects.ca
// ****************************************
// class DefaultNamespace.CustomerInfo
// dynamically generated from class: "CustomerInfo, App_Web_x0jpr5ez, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
// ****************************************


Type.registerNamespace('DefaultNamespace');

DefaultNamespace.CustomerInfo = function DefaultNamespace$CustomerInfo(HomeTimeZoneName, FirstName, LastName, DateOfBirth)
{
  DefaultNamespace.CustomerInfo.initializeBase(this, [FirstName, LastName, DateOfBirth]);

  this._HomeTimeZoneName = HomeTimeZoneName;
}

// HomeTimeZoneName property
DefaultNamespace.CustomerInfo.prototype.get_HomeTimeZoneName = function DefaultNamespace$CustomerInfo$get_HomeTimeZoneName()
{
  return this._HomeTimeZoneName;
}
DefaultNamespace.CustomerInfo.prototype.set_HomeTimeZoneName = function DefaultNamespace$CustomerInfo$set_HomeTimeZoneName(value)
{
  this._HomeTimeZoneName = value;
}

DefaultNamespace.CustomerInfo.registerClass('DefaultNamespace.CustomerInfo', DefaultNamespace.PersonInfo, Sys.IDisposable);
We now have a cso-generated class for the PersonInfo class and the new properties are defined in it. Notice that the CustomerInfo cso-generated class is extending the PersonInfo: the registerClass method call for CustomerInfo specifies PersonInfo as its base class and, inside the constructor, the method initializeBase is called to initialize the PersonInfo fields. Note that the value-creation-script has not changed. For the following object:
CopyCustomer info object
protected void Page_Load(object sender, EventArgs e)
{
    CustomerInfo info = new CustomerInfo("Guy", "Lafleur", new DateTime(1954,2,24), new DataTable(), TimeZone.CurrentTimeZone);

    objectGateway1.SourceObject = info;
}
the value-creation-script for the cso-object is:
CopyValue-creation-script for cso-object of type CustomerInfo
<script type="text/javascript">var aCustomerInfo = new DefaultNamespace.CustomerInfo('Eastern Standard Time','Guy','Lafleur',new Date(-500238000000));</script>

Also notice that the constant field MAX_NAME_LENGTH has made it into the cso-generated class for PersonInfo. The Type Morpher will transfer fields in the cso-generated class only if they are constant (marked with the keyword const in C# and Const in VB.NET) and of course if their type is cso-compatible.

Verify that the class is public

Create substitute classes for generic and nested classes

In this version of the CSO Gateway, generic and nested class cannot be made cso-ready. Some cso-native classes in the Native Type Library are handling generic classes from the .NET Framework but a cso-generated class cannot be created from a generic or nested class. There is no major obstable preventing generic and nested classes to have equivalent cso-generated classes so this will probably be supported in future versions of the CSO Gateway.

Until then, the best workaround if you really need to bring information from instances of a generic or nested class on the client side is to create another non-generic/nested class with similar public properties. This class could be instantiable trough a factory method of the original non-generic/nested class. That method would copy the internal state of the instance of the generic/nested class into a new instance of the non-generic/non-nested class. This new non-generic/non-nested class could now be made cso-ready.

Structs

Structs are morphed into cso-generated classes. There is no such thing as a cso-generated struct. The same rules that applies to classes also applies to structs except those related to inheritance. This is because there is no inheritance with structs. All cso-generated classes originating from a struct have CsoGateway.System.CsoGenerated as their base class.

This is an occasion to demonstrate how to CSO Gateway deals with object composition. Here we will defined an Address struct, make it cso-ready and add a field/property of that type to the CustomerInfo class. The following 6 code snippets shows the Address struct, the Address cso-generated class, the CustomerInfo class, the CustomerInfo cso-generated class, the code behind that creates a CustomerInfo object and the value-defining-script created by the Object Gateway for that object.

CopyAddress struct
[CsoGeneratedType]
public struct Address
{
    public Address(string ad1, string ad2, string zip, string c)
    {
        addressLine1 = ad1;
        addressLine2 = ad2;
        zipCode = zip;
        city = c;
    }

    private string addressLine1;
    public string AddressLine1
    {
        get { return addressLine1; }
    }

    private string addressLine2;
    public string AddressLine2
    {
        get { return addressLine2; }
    }

    private string zipCode;
    public string ZipCode
    {
        get { return zipCode; }
    }

    private string city;
    public string City
    {
        get { return city; }
    }
}
CopyAddress cso-generated class
// ****************************************
// CSO Gateway version 0.7.1.0
// Copyright (C) 2010 Pascal Dufresne
// http://csogateway.codeplex.com
// http://csogateway.metaobjects.ca
// ****************************************
// class DefaultNamespace.Address
// dynamically generated from struct: "Address, App_Web_yxrmygux, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
// ****************************************


Type.registerNamespace('DefaultNamespace');

DefaultNamespace.Address = function DefaultNamespace$Address(AddressLine1, AddressLine2, ZipCode, City)
{
  this._AddressLine1 = AddressLine1;
  this._AddressLine2 = AddressLine2;
  this._ZipCode = ZipCode;
  this._City = City;
}

// AddressLine1 property
DefaultNamespace.Address.prototype.get_AddressLine1 = function DefaultNamespace$Address$get_AddressLine1()
{
  return this._AddressLine1;
}
DefaultNamespace.Address.prototype.set_AddressLine1 = function DefaultNamespace$Address$set_AddressLine1(value)
{
  this._AddressLine1 = value;
}

// AddressLine2 property
DefaultNamespace.Address.prototype.get_AddressLine2 = function DefaultNamespace$Address$get_AddressLine2()
{
  return this._AddressLine2;
}
DefaultNamespace.Address.prototype.set_AddressLine2 = function DefaultNamespace$Address$set_AddressLine2(value)
{
  this._AddressLine2 = value;
}

// ZipCode property
DefaultNamespace.Address.prototype.get_ZipCode = function DefaultNamespace$Address$get_ZipCode()
{
  return this._ZipCode;
}
DefaultNamespace.Address.prototype.set_ZipCode = function DefaultNamespace$Address$set_ZipCode(value)
{
  this._ZipCode = value;
}

// City property
DefaultNamespace.Address.prototype.get_City = function DefaultNamespace$Address$get_City()
{
  return this._City;
}
DefaultNamespace.Address.prototype.set_City = function DefaultNamespace$Address$set_City(value)
{
  this._City = value;
}

DefaultNamespace.Address.registerClass('DefaultNamespace.Address', CsoGateway.System.CsoGenerated, Sys.IDisposable);
CopyCustomerInfo class
[CsoGeneratedType]
public class CustomerInfo : PersonInfo
{
    private DataTable transactions;
    [CsoPropertyExclude]
    public DataTable Transactions
    {
        get { return transactions; }
    }

    public string HomeTimeZoneName
    {
        get { return HomeTimeZone.StandardName; }
    }

    public Address customerAddress;
    public Address CustomerAddress
    {
        get { return customerAddress; }
    }

    public CustomerInfo(string fn, string ln, DateTime dob, DataTable transacs, TimeZone tzr, Address adr)
        : base(fn, ln, dob, tzr)
    {
        transactions = transacs;
        customerAddress = adr;
    }
}
CopyCustomerInfo cso-generated class
// ****************************************
// CSO Gateway version 0.7.1.0
// Copyright (C) 2010 Pascal Dufresne
// http://csogateway.codeplex.com
// http://csogateway.metaobjects.ca
// ****************************************
// class DefaultNamespace.CustomerInfo
// dynamically generated from class: "CustomerInfo, App_Web_rocafcyh, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
// ****************************************


Type.registerNamespace('DefaultNamespace');

DefaultNamespace.CustomerInfo = function DefaultNamespace$CustomerInfo(HomeTimeZoneName, CustomerAddress, FirstName, LastName, DateOfBirth)
{
  DefaultNamespace.CustomerInfo.initializeBase(this, [FirstName, LastName, DateOfBirth]);

  this._HomeTimeZoneName = HomeTimeZoneName;
  this._CustomerAddress = CustomerAddress;
}

// HomeTimeZoneName property
DefaultNamespace.CustomerInfo.prototype.get_HomeTimeZoneName = function DefaultNamespace$CustomerInfo$get_HomeTimeZoneName()
{
  return this._HomeTimeZoneName;
}
DefaultNamespace.CustomerInfo.prototype.set_HomeTimeZoneName = function DefaultNamespace$CustomerInfo$set_HomeTimeZoneName(value)
{
  this._HomeTimeZoneName = value;
}

// CustomerAddress property
DefaultNamespace.CustomerInfo.prototype.get_CustomerAddress = function DefaultNamespace$CustomerInfo$get_CustomerAddress()
{
  return this._CustomerAddress;
}
DefaultNamespace.CustomerInfo.prototype.set_CustomerAddress = function DefaultNamespace$CustomerInfo$set_CustomerAddress(value)
{
  this._CustomerAddress = value;
}

DefaultNamespace.CustomerInfo.registerClass('DefaultNamespace.CustomerInfo', DefaultNamespace.PersonInfo, Sys.IDisposable);
CopyCustomerInfo object
public partial class LearnByExamples_Example10 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Address anAddress = new Address("234 Ste-Catherine St.", "3rd floor, room 110", "92830", "New York");
        CustomerInfo info = new CustomerInfo("Guy", "Lafleur", new DateTime(1954, 2, 24), new DataTable(), TimeZone.CurrentTimeZone, anAddress);

        objectGateway1.SourceObject = info;
    }
}
CopyValue-creation-script for a CustomerInfo cso-object
<script type="text/javascript">var aCustomerInfo = new DefaultNamespace.CustomerInfo('Eastern Standard Time',new DefaultNamespace.Address('234 Ste-Catherine St.','3rd floor, room 110','92830','New York'),'Guy','Lafleur',new Date(-500238000000));</script>

Interfaces

The registerClass method does not verify if the class implements the interfaces given in parameters. In fact, the documetation for the registerInterface explicitely mentions that client side interfaces are not meant to have any members. For that reason, when the Type Morpher morphs an interface into a cso-interface, all members are omitted. Cso-interfaces are used only as marker interfaces to be used with methods of the Type class like Type.getInterfaces , Type.implementsInterface , Type.isImplementedBy and Type.isInterface.

When an interface is marked with the CsoGeneratedTypeAttribute code, it is automatically cso-ready. When an object is passed to the Object Gateway, if any interfaces implemented by this object at any inheritance level is cso-ready, the Type Morpher will first create a corresponding cso-generated interface for it (if not already done), after it will create the cso-generated class (if not already done) for the class or struct that the object is an instance of. The Type.registerClass statement will include the interface in the interfaceTypes parameters.

The cso-generated interface will simply be an empty type declaration followed by a call the the Type.registerInterface method. The following code snippets show an example of a type-defining script for a cso-generated interface. Here is the code for an interface TopInterface and a class B

CopyInterface TopInterface and class B
[CsoGeneratedType]
public interface TopInterface
{
    void TI();
}

[CsoGeneratedType]
public class B : TopInterface
{
    public string TestProperty
    {
        get
        {
            return "Test";
        }
    }

    public void TI()
    {
    }
}
The type-defining-script for the interface TopInterface will look like this:
CopyCso-generated interface example
// ****************************************
// CSO Gateway version 0.7.1.0
// Copyright (C) 2010 Pascal Dufresne
// http://csogateway.codeplex.com
// http://csogateway.metaobjects.ca
// ****************************************
// interface DefaultNamespace.TopInterface
// dynamically generated from interface: "TopInterface, App_Web_eleyhpy5, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
// ****************************************


Type.registerNamespace('DefaultNamespace');

DefaultNamespace.TopInterface = function DefaultNamespace$TopInterface()
{
}

DefaultNamespace.TopInterface.registerInterface('DefaultNamespace.TopInterface');
Even if there are methods in the interface there are no methods in the cso-interface. The type-defining-script for the class B will look like this:
CopyCso-generated class implementing an interface
// ****************************************
// CSO Gateway version 0.7.1.0
// Copyright (C) 2010 Pascal Dufresne
// http://csogateway.codeplex.com
// http://csogateway.metaobjects.ca
// ****************************************
// class DefaultNamespace.B
// dynamically generated from class: "B, App_Web_ut8_ps7x, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
// ****************************************


Type.registerNamespace('DefaultNamespace');

DefaultNamespace.B = function DefaultNamespace$B(TestProperty)
{
  this._TestProperty = TestProperty;
}

// TestProperty property
DefaultNamespace.B.prototype.get_TestProperty = function DefaultNamespace$B$get_TestProperty()
{
  return this._TestProperty;
}
DefaultNamespace.B.prototype.set_TestProperty = function DefaultNamespace$B$set_TestProperty(value)
{
  this._TestProperty = value;
}

DefaultNamespace.B.registerClass('DefaultNamespace.B', CsoGateway.System.CsoGenerated, Sys.IDisposable, DefaultNamespace.TopInterface);
Notice DefaultNamespace.TopInterface is specified in the Type.registerInterface method call.

Enums

Enums are simple enough that they are all cso-ready whether they are defined in the .NET Framework or in your code. The TypeMorpher knows how to generated a cso-generated enum from any of your enums without any action from you. There is nothing to do, decorating the enum with the CsoGeneratedTypeAttribute code attribute is not mandatory.

Let's create a TitleBeforeName enum and add a field/property of that type to the PersonInfo class.

CopyTitle enum
[CsoGeneratedType("MyEnums")]
public enum TitleBeforeName
{
    Mr=0,
    Mrs=1,
    Ms=2,
    Miss=3
}

[CsoGeneratedType]
public abstract class PersonInfo
{
    private TitleBeforeName personTitle;
    public TitleBeforeName PersonTitle
    {
        get{ return personTitle; }
    }

    private string firstName;
    public string FirstName
    {
        get { return firstName; }
    }

    .....
CopyTitle cso-generated enum
// ****************************************
// CSO Gateway version 0.7.1.0
// Copyright (C) 2010 Pascal Dufresne
// http://csogateway.codeplex.com
// http://csogateway.metaobjects.ca
// ****************************************
// enum MyEnums.TitleBeforeName
// dynamically generated from enum: "TitleBeforeName, App_Web_a2sf2pfx, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
// ****************************************


Type.registerNamespace('MyEnums');

MyEnums.TitleBeforeName = function(){};
MyEnums.TitleBeforeName.prototype = 
{
  Mr:0,
  Mrs:1,
  Ms:2,
  Miss:3
}

MyEnums.TitleBeforeName.registerEnum('MyEnums.TitleBeforeName');
CopyValue creation script for a CustomerInfo object
<script type="text/javascript">var aCustomerInfo = new DefaultNamespace.CustomerInfo('Eastern Standard Time',new DefaultNamespace.Address('234 Ste-Catherine St.','3rd floor, room 110','92830','New York'),MyEnums.TitleBeforeName.Mr,'Guy','Lafleur',new Date(-500238000000));</script>

Note that it wasn't necessary to decorate the enum with the CsoGeneratedTypeAttribute code attribute. We did it here to illustrate another use of this code attribute. Notice that the TitleBeforeName cso-generated enum is not in the same namespace as CustomerInfo and PersonInfo. This is because the namespace was explicitely specified in the CsoGeneratedTypeAttribute code attribute as MyEnums.