Can DirectoryObjectBase be made serialisable?

Dec 28, 2011 at 8:25 AM

As mentioned in previous posts (283733 and 283811), I'm building an app in Lightswitch which is basically Silverlight at the client side and WCF RIA Services at the server side.  Both RIA Services and LightSwitch do a lot of code generation for you. 

To make it easier to see what's going on, I've got a test-bed which is a standard Silverlight app using a WCF RIA Service.  I still see the RIA code-generation but I'm in control of the queries that are submitted.

Here are my UserObjects:

    public class UserObject : DirectoryObjectBase
    {
        [Key]
        public Nullable<Guid> objectGuid { get; set; }

        public String commonName { get; set; }
        public String distinguishedName { get; set; }
        public String employeeID { get; set; }
        public String sAMAccountName { get; set; }

        private string _description;
        public String description
        {
            get { return this._description; }
            set
            {
                if (value != this._description)
                {
                    this._description = value;
                    AttributeChanged<UserObject, String>(a => a.description);
                }
            }
        }

I create a DomainServiceClass in the WCF RIA Service which returns an IQueryable of UserObjects:

        [Query(IsDefault = true)]
        public IQueryable<UserObject> GetUserObjects()
        {
            if (context == null)
                context = new DirectoryContext();

            var users = context.Query<UserObject>();
            return users;
        }

This causes VS to create a UserObject class on the client side, which begins like this:

    [DataContract(Namespace="http://schemas.datacontract.org/2004/07/LinqToLdap_RIA_Updates.Web.Entities")]
    public sealed partial class UserObject : Entity
    {
        private string _commonName;
        private string _description;
        private string _distinguishedName;
        private string _employeeID;
        private Nullable<Guid> _objectGuid;
        private string _sAMAccountName;        
        private bool _trackChanges;

I'm only showing you the fields; it's very much more complex than this.  You can see that it has it's own _trackChanges but no _changed.  _trackChanges is manipulated like this:

        /// <summary>
        /// Gets or sets the 'TrackChanges' value.
        /// </summary>
        [DataMember()]
        [Editable(false)]
        [ReadOnly(true)]
        public bool TrackChanges
        {
            get
            {
                return this._trackChanges;
            }
            set
            {
                if ((this._trackChanges != value))
                {
                    this.OnTrackChangesChanging(value);
                    this.ValidateProperty("TrackChanges", value);
                    this._trackChanges = value;
                    this.RaisePropertyChanged("TrackChanges");
                    this.OnTrackChangesChanged();
                }
            }
        }
When I check the value on the client-side, it's false.

If I make the setter public, both the attributes:

        [Editable(false)]
        [ReadOnly(true)]

are removed and _trackChanges is serialised correctly.

What was the reason you decided to make the setter internal?



        
    
Coordinator
Dec 29, 2011 at 6:38 PM
Edited Dec 29, 2011 at 6:41 PM

Originally I wanted to protect users from potentially setting values to null if they only selected a subset of the data and tried to update a partially loaded object.  However, now that I'm revisiting the topic it seems kind of pointless since I only try to update what's been changed anyway.  

I think I'm going to refactor that part of LINQ to LDAP to use an interface.  I'll expose the appropriate properties on DirectoryObjectBase (_changed in this case) as an implementation of IDirectoryObject, but ultimately you should be able to implement the interface and bypass DirectoryObjectBase all together if you want.  So far this is the structure that I'm thinking:

public interface IDirectoryObject
{
     IEnumerable<string> GetChangedAttributes();
     void AttributeChanged(string propertyName);
}

For your client side implementation, you'll want to create a partial class that implements OnDescriptionChanged that adds description to the ChangedAttributes list (that's what it will be called in DirectoryObjectBase).  I should have this checked in this evening as well as a proper fix for the objectGuid.HasValue issue.

Jan 6, 2012 at 3:27 PM

I've seen your update to the source code: I'll download it and have a play and let you know how I get on.

Jan 30, 2012 at 12:16 PM

Sorry about the delay: I've had to build a new test machine and it's taken a while to get everything sorted out.  I'm just installing the last few bits.  For the last time.  I hope.  :-)

Whilst I was testing the FlagsAttribute enum with EnumStoredAsInt I realised that, with the new version of DirectoryObjectBase, TrackChanges defaults to false.  This isn't a problem for me but it might be a breaking change for others.