For WCF I am not passing any entities across the wire.
For each entity I create a wrapper class that represents the data contract for that entity and it exposes only those properties of the entity that I want in that particular contract.
This also helps keep my entity code completely free of .NET 3.0 references as we still have a large installed base of Windows 2000 workstations which cannot use .NET 3.0. ( I know, scary isn't it
).
Here is a very cut down version of my Property Entity
public partial class PropertyEntity : CommonEntityBase, ISerializable
{
// ...other stuff here...
public virtual System.Int32 PropertyId
{
get { return (System.Int32)GetValue((int)PropertyFieldIndex.PropertyId, true); }
set { SetValue((int)PropertyFieldIndex.PropertyId, value); }
}
public virtual System.String AddressLine1
{
get { return (System.String)GetValue((int)PropertyFieldIndex.AddressLine1, true); }
set { SetValue((int)PropertyFieldIndex.AddressLine1, value); }
}
public virtual System.Byte Bedrooms
{
get { return (Nullable<System.Byte>)GetValue((int)PropertyFieldIndex.Bedrooms, false); }
set { SetValue((int)PropertyFieldIndex.Bedrooms, value); }
}
// ...other stuff here...
}
In my WCF Service Library I have a Data Contract wrapper like this :
[DataContract]
public class XaverProperty : IExtensibleDataObject
{
private PropertyEntity _Entity;
public PropertyEntity Entity
{
get { return _Entity; }
set
{
this._Entity = value;
this._Entity.WriteXml(XmlFormatAspect.Compact25, out this._OriginalState);
}
}
public XaverProperty()
{
this.Initialize();
}
public XaverProperty(PropertyEntity p)
{
this._Entity = p;
this._Entity.WriteXml(XmlFormatAspect.Compact25, out this._OriginalState);
}
private void Initialize()
{
this._Entity = new PropertyEntity();
this._Entity.WriteXml(XmlFormatAspect.Compact25, out this._OriginalState);
}
[OnDeserializing]
private void OnDeserializing(StreamingContext sc)
{
this.Initialize();
}
private string _OriginalState = string.Empty;
[DataMember(Order=1)]
public string OriginalState
{
get { return this._OriginalState; }
set
{
this._OriginalState = value;
this._Entity = new PropertyEntity();
this._Entity.ReadXml(this._OriginalState);
}
}
[DataMember(Order=2)]
public string AddressLine1
{
get { return this._Entity.AddressLine1; }
set { this._Entity.AddressLine1 = value; }
}
[DataMember(Order=2)]
public int PropertyId
{
get { return this._Entity.PropertyId; }
set { this._Entity.PropertyId = value; }
}
[DataMember(Order=2)]
public byte Bedrooms
{
get { return this._Entity.Bedrooms; }
set { this._Entity.Bedrooms = value; }
}
// ...other stuff here...
}
It exposes some of the properties of PropertyEntity as part of the DataContract and also a string field called OriginalState which will always be Serialized and Deserialized first.
In my service contract I have GetProperty(int propertyID) and SaveProperty(Property p).
When GetProperty is called it returns a Property data contract which also contains the original entity's complete state.
When SaveProperty is called the original state is deserialized into the Entity class first by the DataContractSerializer and then each of the remaining DataMember fields is set.
This means that the Property object I receive contains a PropertyEntity that reflects the exact changes the user has made as if they had made them to a local or MarshallByRef object I can use all the right IAuditors, IAuthorizers and IValidators to manage the changes as the DataContractSerializer makes them.
I may look at encrypting the OriginalState plus some other features but this is my general approach at the moment.