Saturday, June 09, 2007

The Windows Communication Foundation (WCF) has some interesting challenges when it comes to serialization. The model chosen by Microsoft does not work out-of-the-box and doesn't obey attributes such as [XmlIgnore] and alike. So, while you're classes might serialize perfectly in SOAP scenarios you'll be scratching your head when it comes to WCF serialization (in most cases). Of course, EntitySpaces supports binary serialization and you can certainly very easily use our binary serialization for WCF remoting when you are in control of both the client and server.

EntitySpaces is sporting a new tab on the "Generated Master" template in our upcoming ES2007 maintenance release. This release will most likely arrive on June 23rd, however, an internal beta will be provided for those doing WCF now, no public beta will be posted. If you are interested in working with our WCF support please email us support@entityspaces.net

So, if you are doing WCF programming this new release is definitely for you. 

 


Using the Employees table from Microsoft's Northwind database let's take a look at how to use the EntitySpaces WCF proxy stub classes. You can use the same proxy stub class on both the server and the client side. The proxy stub classes will automatically be placed in your generated "single file" during the code generation process. Two class will be created:

  1. EmployeesProxyStub
  2. EmployeesCollectionProxyStub

These are both lightweight intelligent wrappers that cause your EntitySpaces objects to be serialized correctly when used in WCF communications scenarios. This post is only going to cover the EmployeesProxyStub class, the EmployeesCollectionProxyStub will be covered in a follow up post. However, the collection proxy stub code has already been written and tested.

The EmployeesProxyStub

This is the wrapper for your single entity classes. You can use the proxy stub class to return data from the server to the client simply by executing this code.

 

public EmployeesProxyStub SomeMethod(int id)
{
    Employees employee = new Employees();
    employee.LoadByPrimaryKey(id);
    return new EmployeesProxyStub(employee);
}

 

The XML will look something like this. Notice that only the non-null columns are returned. This is because we checked the "EmitDefaultValue=False" checkbox on the template, otherwise there would have been place holder elements in the XML for those columns that were null.

 

<Employees xmlns="http://tempuri.org/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <EmployeeID>257</EmployeeID>
    <LastName>Goo</LastName>
    <FirstName>foo</FirstName>
    <esRowState>Unchanged</esRowState>
</Employees>

 

This is an example of the generated proxy stub class. 

 

[DataContract(Namespace = "http://tempuri.org/", Name = "Employees")]
[Serializable]
public class EmployeesProxyStub
{
    public EmployeesProxyStub(Employees obj)
    {
        this.entity = obj;
    }

    [DataMember(Order = 1, EmitDefaultValue = false)]  // EmitDefaultValue -> see checkbox above
    public System.Int32? EmployeeID
    {
        get
        {
            if (this.Entity.es.IsDeleted)
                return (System.Int32?)this.Entity.
                    GetOriginalColumnValue(EmployeesMetadata.PropertyNames.EmployeeID);
            else
                return this.Entity.EmployeeID;
        }
       set { this.Entity.EmployeeID = value; }
    }

    [DataMember(Order = 2, EmitDefaultValue = false)]  // EmitDefaultValue -> see checkbox above
    public System.String FirstName
    {
        get
        {
            if (this.Entity.es.IsDeleted)
                return null;
            else
                return this.Entity.FirstName;
        }
        set { this.Entity.FirstName = value; }
    }

    // and more properties are in here ....

    [DataMember(Order=19)]
    public string esRowState  // Present only if "Include Added/Modified/Deleted" is clicked
    {
        get
        {
            return this.Entity.es.RowState.ToString();
        }

        set
        {
            switch (value)
            {
                case "Unchanged":
                    this.Entity.AcceptChanges();
                    break;

                case "Added":
                    break;

                case "Modified":
                    this.Entity.AcceptChanges();
                    this.Entity.es.RowState = DataRowState.Modified;
                    break;

                case "Deleted":
                    this.Entity.AcceptChanges();
                    this.Entity.MarkAsDeleted();
                    break;
            }
        }
    }

    public Employees Entity
    {
        get
        {
            if (this.entity == null)
            {
                this.entity = new Employees();
            }

            return entity;
        }

        set
        {
            this.entity = value;
        }
    }

    [NonSerialized]
    public Employees entity;

}

 

Now let's receive our Employees packet on the client, modify it, and send it back to the server.

 

EmployeesProxyStub proxy = call SomeMethod(); ...
Employees emp = proxy.Entity;  // grab the true Employees object now

emp.FirstName = "ES Rocks!";

call SendDataBackToClient(proxy);

 

The Server will now receive this XML packet. Notice that the esRowState is now Modified. The esRowState is interpreted in the set accessor of the proxy stub in the esRowState property to ensure that the entity is in the proper state after deserialization.

 

<Employees xmlns="http://tempuri.org/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <EmployeeID>257</EmployeeID>
    <LastName>Goo</LastName>
    <FirstName>ES Rocks!</FirstName>
    <esRowState>Modified</esRowState>
</Employees>

 

On the server you would deserialize just as we did on the client and then call Save(). Very simple. We are thinking of adding another checkbox in the template so that the proxy stubb class will only send dirty columns back when modified. For Deleted records only the primary key(s) are sent with an esRowState value of Deleted. Again, you can simply call save, no MarkAsDeleted() call is necessary, it's already been done for you.

From mobile devices to large scale enterprise solutions in need of serious transaction support, EntitySpaces can meet your needs. Whether you’re writing an ASP.NET application with medium trust requirements, or a Windows.Forms application, the EntitySpaces architecture is there for you. EntitySpaces is provider independent, which means that you can run the same binary code against any of the supported databases.EntitySpaces is available in both C# and VB.NET. EntitySpaces uses no reflection, no XML files, and sports a tiny foot print of less than 200k. Pound for pound, EntitySpaces is one tough, dependable .NET architecture.

The EntitySpaces Team
--

EntitySpaces LLC
Persistence Layer and Business Objects for Microsoft .NET
http://www.entityspaces.net