Showing posts with label Patterns. Show all posts
Showing posts with label Patterns. Show all posts

Wednesday, May 11, 2011

Enhancing Reflection with IL Instructions



Download sample ILInstruction class
Download sample MethodBaseEx class

As I embarked in a quest to bring multi-inheritance to versions of the .NET framework pre-.NET 4 (more on this later) I noticed that reflection is not really user friendly when it comes down to getting IL instructions. Before I can get my groove on and talk about multi-inheritance, I figured it would be worthwhile to extend the reflection classes a little to make it easier to work with IL.



The ILInstruction Class


The first thing we'll need is a simple class that will hold some useful information about IL instructions. Let's call it the "ILInstruction" class:


 public sealed class ILInstruction
    {
        public int Offset { get; set; }
        public OpCode OpCode { get; set; }
        public object Arguments { get; set; }

        public bool IsMethodCall { get { return this.Arguments is MethodInfo; } }
        public bool IsConstructorCall { get { return this.Arguments is MethodInfo; } }

        public override string ToString()
        {
            return string.Format("{0} : {1}", this.Offset.ToString("X4"), this.OpCode);
        }
    }

fairly straight forward. The most important properties here are the OpCode and the Arguments which is all you really need. The rest are nice to haves.




IL byte array -> IL Instructions


Now we should move on to populating a bunch of these with IL data. Unfortunately the only means that you have to get IL is by using MethodBase's GetMethodBody method. This method returns a class with a couple of useful properties such as LocalVariables and MaxStack. But more importantly, this method allows you to call GetILAsByteArray which returns the IL's byte array. This is not very useful as is, but it's what we need to populate instances of our newly defined ILInstruction class.


A couple of notes about IL byte arrays: OpCodes are 2 bytes long (I never understood this decition since there aren't more than 255 OpCodes and chances are there never will be) but for optimization purposes, OpCodes in the 0-255 range get reduced to 1 byte when converted to binary data. Moreover, for some reason even though there are only 226 OpCodes some of them have a value greater than 255. Therefore you cannot rely on a fixed number of bytes that represent an OpCode. The other important thing to note is that not all OpCodes take arguments, but those that do usually are represented as a 1-4 bytes of data and its meaning differ from OpCode to OpCode.


All of that said, now that we have the IL and we understand what it means, we can start looping through it byte by byte and interpreting the meaning of each byte like so:


 byte[] bytes = methodBody.GetILAsByteArray();
  
                int offset = 0;
                while (offset < bytes.Length)
                {
                    ILInstruction instruction = new ILInstruction();
                    instruction.Offset = offset;
                    instruction.OpCode = _opCodes[(short)bytes[offset] == 0xfe ? (short)(bytes[offset + 1] | 0xfe00) : (short)bytes[offset]]; // note that some opcodes have a value greater than 255, so in those cases we take the following byte as well
                    
                    if ((short)bytes[offset] == 0xfe)
                        offset += 2;
                    else
                        offset++;

                    switch (instruction.OpCode.OperandType)
                    {
      }
  }

The code bellow illustrates how to figure out what the OpCode for an instruction is, but after reading an OpCode we must also figure out wether arguments data follows and if so we must interpret the data like this:

 switch (instruction.OpCode.OperandType)
                    {
                        case OperandType.InlineBrTarget:
                            offset += 4;
                            break;

                        case OperandType.InlineField:
                            instruction.Arguments = methodBase.Module.ResolveField(bytes.GetInt32(offset));
                            offset += 4;
                            break;

                        case OperandType.InlineI:
                            offset += 4;
                            break;

                        case OperandType.InlineI8:
                            offset += 8;
                            break;

                        case OperandType.InlineMethod:
                            int metaDataToken = bytes.GetInt32(offset);

                            Type[] genericMethodArguments = null;
                            if (methodBase.IsGenericMethod == true)
                                genericMethodArguments = methodBase.GetGenericArguments();

                            instruction.Arguments = methodBase.Module.ResolveMethod(metaDataToken, methodBase.DeclaringType.GetGenericArguments(), genericMethodArguments);
                            offset += 4;
                            break;

                        case OperandType.InlineNone:
                            break;

                        case OperandType.InlineR:
                            offset += 8;
                            break;

                        case OperandType.InlineSig:
                            offset += 4;
                            break;

                        case OperandType.InlineString:
                            instruction.Arguments = methodBase.Module.ResolveString(bytes.GetInt32(offset));
                            offset += 4;
                            break;

                        case OperandType.InlineSwitch:
                            int count = bytes.GetInt32(offset) + 1;
                            offset += 4 * count;
                            break;

                        case OperandType.InlineTok:
                            offset += 4;
                            break;

                        case OperandType.InlineType:
                            offset += 4;
                            break;

                        case OperandType.InlineVar:
                            offset += 2;
                            break;

                        case OperandType.ShortInlineBrTarget:
                            instruction.Arguments = typeof(Label);
                            offset += 1;
                            break;

                        case OperandType.ShortInlineI:
                            offset += 1;
                            break;

                        case OperandType.ShortInlineR:
                            offset += 4;
                            break;

                        case OperandType.ShortInlineVar:
                            offset += 1;
                            break;

                        default:
                            throw new NotImplementedException();
                    }

The only important thing to take away from this piece of code is that methods, fields and constats are stored in the module's metadata, and the IL byte array provides a unique identifier for the metadata table. So what we must do is call the corresponding ResolveX to get a meaningful object (Depending on what OpCode we are dealing with the argument will have a different meaning and should be looked up on a different metadata table).

So there you have it folks. This is how you can turn IL byte arrays to meaningful Object-Oriented code. Unfortunately this implementation does not account for every single scenarion that you can encounter and it does not implement all operand types. But stay tooned for a complete CodePlex project with all the bells and whistles needed to create your own Reflector like software.

Saturday, June 19, 2010

MMV Lib now available at CodePlex



The Multiuse-Model View examples from my previous posts can now be found in one complete project at codeplex: mmv.codeplex.com. Enjoy!



Wednesday, May 19, 2010

MultiuseModel-View (MMV) Object modeling pattern with WPF and WCF: Wrapping it up



In my previous articles, I described how to create an ObservableObject to wrap notification functionality, a DatabaseObject to wrap calls to the DB, and a CommunicationObject to wrap client-server communication code. In this brief article I will describe how to wrap it all together under one common API.



The MultiuseObject<T>


The purpose of this class is very simple: to make the appropiate API call depending on where the code is executing. In other words, when calling the Save method, we want a smart object to send it over the wire to the server if the code is executing on the client or call the ORM layer to persist the data into the database if the code is executing on the server. To accomplish this we first need to provide the library info regarding where the code is executing. We start by defining an enum with the possible choices:


public enum ServiceType
{
 Client = 0,
 WebServer = 1,
 AppServer = 2
}

And then we define a utility class to extract the values from the config file:


internal sealed class CommunicationConfiguration
{
 private static object _SynchLock = new object();
        private static CommunicationConfiguration _Current;
        public static CommunicationConfiguration Current
        {
            get
            {
                if (_Current == null)
                {
                    lock (_SynchLock)
                    {
                        _Current = new CommunicationConfiguration();
                    }
                }
                return (_Current);
            }
        }

        private ServiceType? _CurrentServiceType;
        public ServiceType CurrentServiceType
        {
            get
            {
                if (ConfigurationManager.AppSettings["ServiceType"] == null)
                    throw new InvalidConfigurationException(string.Format("ServiceType is a required Application Setting. Acceptable values are: {0}", string.Join(", ", Enum.GetNames(typeof(ServiceType)))));
                if (_CurrentServiceType == null)
                    _CurrentServiceType = (ServiceType)Enum.Parse(typeof(ServiceType), ConfigurationManager.AppSettings["ServiceType"]);
                return (_CurrentServiceType.Value);
            }
        }

        private CommunicationConfiguration()
        {
        }
    }
}

Now all we need to do is ensure that the applications using the library define appropiate configuration values:


<appSettings>
<add key="ServiceType" value="Client"/>
</appSettings>

The only thing left here is to create a class that inherits CommunicationObject<T> and uses the configuration to determine which call it should make:


public abstract class MultiuseObject<T> : CommunicationObject<T>
{
        public void Load(object primaryKeyValue)
        {
            if (CommunicationConfiguration.Current.CurrentServiceType == CommunicationConfiguration.ServiceType.Client)
                LoadFromServer(primaryKeyValue);
            else if (CommunicationConfiguration.Current.CurrentServiceType == CommunicationConfiguration.ServiceType.WebServer)
                LoadFromServer(primaryKeyValue);
            else if (CommunicationConfiguration.Current.CurrentServiceType == CommunicationConfiguration.ServiceType.AppServer)
                LoadFromDB(primaryKeyValue);
        }

        public void Save()
        {
            if (CommunicationConfiguration.Current.CurrentServiceType == CommunicationConfiguration.ServiceType.Client)
                SaveToServer();
            else if (CommunicationConfiguration.Current.CurrentServiceType == CommunicationConfiguration.ServiceType.WebServer)
                SaveToServer();
            else if (CommunicationConfiguration.Current.CurrentServiceType == CommunicationConfiguration.ServiceType.AppServer)
                SaveToDB();
        }
}

In a nutshell, this is all there is to building a robust object modeling library!


Note: I did not include source code files for these classes because I will be packaging up all the sample files into a codeplex project. Stay tuned!!





Sunday, April 4, 2010

MultiuseModel-View (MMV) Object modeling pattern with WPF and WCF: The Other Side



Download sample CommunicationObject File
Download sample ICommunicationServiceContract File
Download sample CommunicationCollectionEx File
Download sample CommunicationService File
Download sample ServiceClient File
Download sample NetDataContractSerializerBehavior File
Download sample NetDataContractSerializerElement File
Download sample NetDataContractSerializerOperationBehavior File



In my previous articles, I described how to create a DatabaseObject<T> that allows the inheritors to maintain a persistent state on a database. In this article I will show you how to create an object that sends itself across the wire from and to the client using WCF.



Fore note


Because of the complexity involved in serializing objects and sending them through the wire between servers or between a server and a client, we cannot simply wrap all the functionality into one class. Instead we'll have to create several classes that work together under the umbrella of a "facade" class (our CommunicationObject<T>). Moreover, much like the database functionality provided by DatabaseObject<T> and DatabaseCollectionEx, we'll have to provide both single instance and collection implementations of our communication classes.



The CommunicationObject<T> Class



The CommunicationObject<T> is a very simple class, since by itself it doesn't do much other than relying on other classes to send itself to or get itself from the server. Much like the DatabaseObject<T>, the CommunicationObject<T> provides only two methods: LoadFromServer and SaveToServer.


public abstract class CommunicationObject : DatabaseObject
{
    public void LoadFromServer(object primaryKeyValue)
    {
        ServiceClient client = new ServiceClient();
        object loaded = client.ContractChannel.LoadObject(typeof(T), primaryKeyValue);
        foreach (PropertyInfo pi in typeof(T).GetProperties())
            pi.SetValue(this, pi.GetValue(loaded, null), null);
    }

    public void SaveToServer()
    {
        ServiceClient client = new ServiceClient();
        // We call CreateOverridenType first to ensure that the server has loaded the extended type of T on the dynamic assembly.
        // Failure to do so would result in a CommunicationException because the deserializer would not be able to find the type.
        client.ContractChannel.CreateOverridenType(typeof(T));

        object reloaded = client.ContractChannel.SaveObject(this);
        foreach (PropertyInfo pi in typeof(T).GetProperties())
            pi.SetValue(this, pi.GetValue(reloaded, null), null);
    }
}

What's important to note here is that these methods themselves are the ones who instantiate a service client. In other words, we are wrapping the functionality that typically lives elsewhere in our applications and usually is spread around in multiple places into just one class that any of the business objects can inherit from. Other than that, the CommunicationObject ensures that the object instance properties are updated every time an object is loaded or saved.


The ServiceClient uses the ICommunicationService interface as its contract. The ICommunicationService interface defines methods for both single instance objects as well as collections and it also offers the ability for the caller to create an overridden type remotely (this is important to ensure that both the client and the server have the same types loaded).


[ServiceContract]
public interface ICommunicationServiceContract
{
    // CommunicationObject Methods

    [OperationContract]
    void CreateOverridenType(Type databaseObjectType);

    [OperationContract]
    object LoadObject(Type databaseObjectType, object primaryKeyValue);

    [OperationContract]
    object SaveObject(object objectToSave);

    // CommunciationCollection Methods

    [OperationContract]
    object LoadCollection(Type databaseObjectType);

    [OperationContract]
    object LoadCollectionWithCriteria(Type databaseObjectType, ICriterion[] criteria);

    [OperationContract]
    object SaveCollection(object collectionToSave);

}


CommunicationCollectionEx


Thanks to extension methods in .Net 3.5 we don't have to create our own collection class to extend the functionality of each type of collection (List, Dictionary, etc). Instead we can just use a bunch of extension methods that operate on ICollection<T> to provide the functionality we want.


public static class CommunicationCollectionEx
{
    public static void LoadFromServer(this ICollection collection)
    {
        // we ensure that the returning objects have a corresponding type loaded.
        ObservableObject.CreateOverridenType();

        ServiceClient client = new ServiceClient();
        object loaded = client.ContractChannel.LoadCollection(typeof(T));
        foreach (T item in (ICollection)loaded)
            collection.Add(item);
    }

    public static void LoadFromServer(this ICollection collection, params ICriterion[] criteria)
    {
        // we ensure that the returning objects have a corresponding type loaded.
        ObservableObject.CreateOverridenType();

        ServiceClient client = new ServiceClient();
        object loaded = client.ContractChannel.LoadCollectionWithCriteria(typeof(T), criteria);
        foreach (T item in (ICollection)loaded)
            collection.Add(item);
    }

    public static void SaveToServer(this ICollection collection)
    {
        // we ensure that the returning objects have a corresponding type loaded.
        ObservableObject.CreateOverridenType();

        ServiceClient client = new ServiceClient();
        // We also ensure that the object has been overriden on the server as well.
        client.ContractChannel.CreateOverridenType(typeof(T));
        object loaded = client.ContractChannel.SaveCollection(collection);
        collection.Clear();
        foreach (T item in (ICollection)loaded)
            collection.Add(item);
    }
}

As you can see, there are also two basic methods (one is overloaded) defined in this class: LoadFromServer and SaveToServer. Much like their single-instance counterparts, these methods create an instance of SeviceClient to call the appropriate operations defined by ICommunicationServiceContract. The overloaded LoadFromDatabase object also allows for defining a set of criteria to reduce the resultset.



Implementing CommunicationService


Previously I talked about the ICommunicationServiceContract as the provider of functionality to get and save objects across the wire. This interface needs an implementation, and for reusability purposes we want to define it as part of our core classes.


public class CommunicationService : ICommunicationServiceContract
{
    public void CreateOverridenType(Type databaseObjectType)
    {
        ObservableObject.CreateOverridenType(databaseObjectType);
    }

    public object LoadObject(Type databaseObjectType, object primaryKeyValue)
    {
        object databaseObject = Activator.CreateInstance(ObservableObject.CreateOverridenType(databaseObjectType));
        databaseObjectType.GetMethod("LoadFromDB").Invoke(databaseObject, new object[] { primaryKeyValue });
        return (databaseObject);
    }

    public object SaveObject(object objectToSave)
    {
        objectToSave.GetType().GetMethod("SaveToDB").Invoke(objectToSave, null);
        return (objectToSave);
    }

    public object LoadCollection(Type databaseObjectType)
    {
        object list = Activator.CreateInstance(typeof(List<>).MakeGenericType(databaseObjectType));
        MethodInfo loadFromDBInfo = (from mi in typeof(DatabaseCollectionEx).GetMethods() where mi.Name == "LoadFromDB" && mi.GetParameters().Length == 1 select mi).First().MakeGenericMethod(databaseObjectType);
        loadFromDBInfo.Invoke(null, new object[] { list }); ;
        return (list);
    }

    public object LoadCollectionWithCriteria(Type databaseObjectType, ICriterion[] criteria)
    {
        object list = Activator.CreateInstance(typeof(List<>).MakeGenericType(databaseObjectType));
        MethodInfo loadFromDBInfo = (from mi in typeof(DatabaseCollectionEx).GetMethods() where mi.Name == "LoadFromDB" && mi.GetParameters().Length == 2 select mi).First().MakeGenericMethod(databaseObjectType);
        loadFromDBInfo.Invoke(null, new object[] { list, criteria }); ;
        return (list);
    }

    public object SaveCollection(object collectionToSave)
    {
        MethodInfo saveToDBInfo = (from mi in typeof(DatabaseCollectionEx).GetMethods() where mi.Name == "SaveToDB" && mi.GetParameters().Length == 1 select mi).First().MakeGenericMethod(collectionToSave.GetType().GetGenericArguments()[0]);
        saveToDBInfo.Invoke(null, new object[] { collectionToSave }); ;
        return (collectionToSave);
    }
}

There isn't much of a mystery about this class. It is fairly simple. By using reflection we invoke the appropiate DatabaseObject<T> or DatabaseCollectionEx method to get or save data to the database.



Helper Classes


There are a number of supporting classes that we need to make the classes described above work properly with WCF. The first one being the ServiceClient class we used in our CommunicationObject and CommunicationCollectionEx classes. This class is very simple since all it does is extend the System.ServiceModel.ClientBase class and provides a public accessor to the Channel casted to ICommunicationServiceContract.


internal sealed class ServiceClient : System.ServiceModel.ClientBase where T : class
{
    public T ContractChannel
    {
        get { return ((T)Channel); }
    }

    public ServiceClient()
    {
    }

    public ServiceClient(string endpointConfigurationName) :
        base(endpointConfigurationName)
    {
    }

    public ServiceClient(string endpointConfigurationName, string remoteAddress) :
        base(endpointConfigurationName, remoteAddress)
    {
    }

    public ServiceClient(string endpointConfigurationName, EndpointAddress remoteAddress) :
        base(endpointConfigurationName, remoteAddress)
    {
    }

    public ServiceClient(Binding binding, EndpointAddress remoteAddress) :
        base(binding, remoteAddress)
    {
    }
}

Also, other important helper classes are the NetDataContractSerializerX set of classes. These being the NetDataContractSerializerElement, NetDataContractSerializerBehavior and NetDataContractSerializerOperationBehavior which are in charge of serializing objects using the NetDataContractSerializer instead of the traditional DataContractSerializer.


public class NetDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
    public NetDataContractSerializerOperationBehavior(OperationDescription operationDescription)
        : base(operationDescription)
    {
    }
    public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList knownTypes)
    {
        return new NetDataContractSerializer();
    }
    public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList knownTypes)
    {
        return new NetDataContractSerializer();
    }
}

public class NetDataContractSerializerBehavior : Attribute, IServiceBehavior, IEndpointBehavior
{
    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection endpoints, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        foreach (var endpoint in serviceDescription.Endpoints)
            this.RegisterContract(endpoint);
    }

    public void Validate(ServiceEndpoint endpoint)
    {
    }

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
        this.RegisterContract(endpoint);
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
    }

    protected void RegisterContract(ServiceEndpoint endpoint)
    {
        foreach (OperationDescription desc in endpoint.Contract.Operations)
        {
            var dcsOperationBehavior = desc.Behaviors.Find();
            if (dcsOperationBehavior != null)
            {
                int idx = desc.Behaviors.IndexOf(dcsOperationBehavior);
                desc.Behaviors.Remove(dcsOperationBehavior);
                desc.Behaviors.Insert(idx, new NetDataContractSerializerOperationBehavior(desc));
            }
        }
    }
}

public class NetDataContractSerializerElement : BehaviorExtensionElement
{
    public override Type BehaviorType
    {
        get { return typeof(NetDataContractSerializerBehavior); }
    }

    protected override object CreateBehavior()
    {
        return new NetDataContractSerializerBehavior();
    }
}

With all these things in place, all we need to do is ensure that these assemblies are referenced by both our client and our server projects. If so, calling the "SaveToServer" or "GetFromServer" methods of a class that inherits CommunicationObject<T> should yield the expected results.


In my next article, I'll demonstrate how to extend client-server functionality to allow for multi-tier services and how to put everything together into a nice MultiuseObject<T>.




Monday, February 1, 2010

MultiuseModel-View (MMV) Object modeling pattern with WPF and WCF: Hibernation



Download sample ObservableSet File
Download sample ObservableSetType File
Download sample ObservableCollectionType File
Download sample DatabaseObject File
Download sample DatabaseCollection File
Download sample DatabaseSet File
Download sample DatabaseCollectionEx File



In my previous article I went over how to break up a multiuse object into logical parts. In this article I will talk about how to build an object-oriented data layer using a DatabaseObject and NHibernate.



About NHibernate


NHibernate is an Object-Relational Mapping (ORM) for .NET. I've used it extensively and to be honest it's the best library for manipulating data that I've dealt with by far. There are a few different ways in which you can map a class with NHibernate: using XML files, using Attributes, or using a mapping classes with Fluent Hibernate. Personally I use Attributes since it is the least verbose choice and it is also the easiest to extend.


NHibernate is very powerful when it comes down to mapping collections, however, it is also very particular about how it handles collections internally (specifically speaking, it is particular about the lazy-loading functionality). Out of the box NHibernate lets you only use either IList<T> or ISet<T> for collections, and behind the scenes it creates an instance of a custom type (PersistantGenericBag<T>). For WPF applications using IList or ISet is inconvenient because of the lack of change notifications. Ideally we would like to use ObservableCollection instead.


While you cannot use ObservableCollection<T> by default, NHibernate allows you to define your own custom collection. And that's exactly what we should do: we have to create an ObservableSet<T> (which is a HashSet<T> collection that implements INotifyCollectionChanged) and we have to write two custom classes to play nicely with NHibernate: ObservableCollectionType and ObservableSetType.


public class ObservableSet<T> : HashedSet<T>, ISet<T>, INotifyCollectionChanged
{
 public event NotifyCollectionChangedEventHandler CollectionChanged;

 // WPF requires the list index to be passed back to
 // itself when removing an item from the collection.
 // Sets have no indices, so they are hereby added.
 public int IndexOf(T item) { return addOrder.IndexOf(item); }

 private IList<T> addOrder = new List<T>();

 public override bool Add(T item)
 {
  bool isChanged = base.Add(item);
  if (isChanged)
  {
   addOrder.Add((T)item);
   OnCollectionChanged(NotifyCollectionChangedAction.Add, item);
  }
  return isChanged;
 }

 public override bool Remove(T item)
 {
  // WPF requires the list index to be passed back to itself:
  int index = IndexOf(item);
  bool isChanged = base.Remove(item);
  if (isChanged)
  {
   addOrder.Remove((T)item);
   if (CollectionChanged != null)
    CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, (object)item, index));
  }
  return isChanged;
 }

 public override void Clear()
 {
  base.Clear();
  addOrder.Clear();
  OnCollectionChanged(NotifyCollectionChangedAction.Reset, null);
 }

 /// <summary>
 /// Raises the <see cref="CollectionChanged"/> event to indicate that item(s)
 /// have been added to, or removed from, this collection.
 /// </summary>
 protected virtual void OnCollectionChanged(NotifyCollectionChangedAction action, object changedItem)
 {
  if (CollectionChanged != null)
   CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, changedItem));
 }
}

internal class ObservableCollectionType<T> : IUserCollectionType
{
        public bool Contains(object collection, object entity)
        {
            return ((IList<T>)collection).Contains((T)entity);
        }

        public IEnumerable GetElements(object collection)
        {
            return (IEnumerable)collection;
        }

        public object IndexOf(object collection, object entity)
        {
            return ((IList<T>)collection).IndexOf((T)entity);
        }

        public object Instantiate(int anticipatedSize)
        {
            return new ObservableCollection<T>();
        }

        public IPersistentCollection Instantiate(ISessionImplementor session, ICollectionPersister persister)
        {
            return new DatabaseCollection<T>(session);
        }

        public object ReplaceElements(object original, object target, ICollectionPersister persister, object owner, IDictionary copyCache, ISessionImplementor session)
        {
            IList<T> result = (IList<T>)target;
            result.Clear();
            foreach (object item in ((IEnumerable)original))
                result.Add((T)item);
            return result;
        }

        public IPersistentCollection Wrap(ISessionImplementor session, object collection)
        {
            return new DatabaseCollection<T>(session, (ObservableCollection<T>)collection);
        }
}

internal class ObservableSetType<T> : IUserCollectionType
{
        public bool Contains(object collection, object entity)
        {
            return ((ISet<T>)collection).Contains((T)entity);
        }

        public IEnumerable GetElements(object collection)
        {
            return (IEnumerable)collection;
        }

        public object IndexOf(object collection, object entity)
        {
            return -1;
        }

        public object Instantiate(int anticipatedSize)
        {
            return new ObservableSet<T>();
        }

        public IPersistentCollection Instantiate(ISessionImplementor session, ICollectionPersister persister)
        {
            return new DatabaseSet<T>(session);
        }

        public object ReplaceElements(object original, object target, ICollectionPersister persister, object owner, IDictionary copyCache, ISessionImplementor session)
        {
            ISet<T> result = (ISet<T>)target;
            result.Clear();
            foreach (object item in ((IEnumerable)original))
                result.Add((T)item);
            return result;
        }

        public IPersistentCollection Wrap(ISessionImplementor session, object collection)
        {
            return new DatabaseSet<T>(session, (ObservableSet<T>)collection);
        }
}


The DatabaseObject<T> Class


When using NHibernate, creating a class that could load or save an object is extremely trivial. The implementation of a DatabaseObject<T> class would look something like this:


public abstract class DatabaseObject<T> : ObservableObject<T>
{
        public void Save()
        {
            ISession session = NHibernateHelper.Configuration.BuildSessionFactory().OpenSession();
            session.SaveOrUpdate(this);
            session.Flush();
            session.Close();
        }

        public void Load(object id)
        {
            ISession session = NHibernateHelper.Configuration.BuildSessionFactory().OpenSession();
            T loaded = (T)session.Load(ObservableObject.CreateOverridenType(typeof(T)), id);
            foreach (PropertyInfo pi in typeof(T).GetProperties())
                pi.SetValue(this, pi.GetValue(loaded, null), null);
            session.Flush();
            session.Close();
        }
}

There are a couple of things worthwhile noting about the DatabaseObject<T> class.


First of all, notice that we flush and close the session every time we load or save an object. This is important because the "lazy load" functionality in NHibernate requires a session to be open for as long as values haven't been loaded. For client-server apps this is a very bad thing: for one we don't want to maintain a session open (which implies an open connection to the database) while data is transfered from the server to the client and while the client loads the remainder of the data. And for two, depending on what type of data transfer protocol you are using, proxy objects might not be supported at all, resulting in incomplete data on the client. Therefore what we want is to transfer all the data from the server to the client at once. This is the reason why we don't support lazy-loading on this framework. However, it is altogether possible that you might be writing a 2-tier app where the client is sitting right on top of the database, and for this scenario I will show you how to modify the DatabaseObject to support lazy-loading on a future article.


Second, notice that on the first line of the Save and Load methods, there is a reference to the NHibernateHelper class. This class is the real deal for using NHibernate in conjunction with our previously written ObservableObject<T> class. The purpose of the NHibernateHelper class is simply to generate and keep track of object maps. It contains a public Configuration property so that any class that wants to create a session does so with the proper mappings.


internal sealed class NHibernateHelper
 {
        private const string CollectionTypeXmlAttribute = "collection-type";
        private const string ClassXmlAttribute = "class";
        private static readonly string[] RelationsXmlElements = { "many-to-many", "one-to-many" };

        private static readonly Dictionary<Type, Type> _MappedClasses;
        private static readonly Dictionary<string, Type> _CollectionElementsToTypes;
        private static readonly Configuration _Configuration;
        public static Configuration Configuration { get { return (_Configuration); } }

        static NHibernateHelper()
        {
            _MappedClasses = new Dictionary<Type, Type>();
            _CollectionElementsToTypes = new Dictionary<string, Type>();
            _CollectionElementsToTypes["bag"] = typeof(ObservableCollectionType<>); 
            _CollectionElementsToTypes["list"] = typeof(ObservableCollectionType<>);
            _CollectionElementsToTypes["set"] = typeof(ObservableSetType<>);
            _Configuration = new Configuration();
            _Configuration.Configure();

            // We first create overriden types for all classes that have a mapping. 
            // This is so that if there is a reference to another type (call it A) within a given type (call it B) 
            // we already have created the type A's overriden type and we can substitue B's map with the derived type.
            foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                foreach (Type type in assembly.GetTypes())
                {
                    if (type.GetCustomAttributes(typeof(ClassAttribute), false).Length > 0)
                    {
                        Type currentType = type;
                        Type overridenType = ObservableObject.CreateOverridenType(currentType);

                        _MappedClasses[currentType] = overridenType;
                    }
                }
            }

            foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                foreach (Type type in assembly.GetTypes())
                {
                    if (type.GetCustomAttributes(typeof(ClassAttribute), false).Length > 0) // This type defines a map
                    {
                        Type currentType = type;
                        Type overridenType = _MappedClasses[currentType];

                        // create a map XML string.
                        MemoryStream stream = new MemoryStream();
                        HbmSerializer.Default.Validate = true;
                        HbmSerializer.Default.Serialize(stream, currentType);
                        stream.Position = 0;

                        string currentTypeMap = new StreamReader(stream).ReadToEnd();
                        stream.Close();


                        // Collections are tricky business with NHibernate. By default NHibernate likes to deal with IList because internally
                        // it implements it's own custom persistant collections. What we need to do here is to add the "collection-type" attribute 
                        // of the X-to-many elements to point to our custom collection which implements INotifyCollectionChanged.
                        //XmlTextReader reader = new XmlTextReader(new MemoryStream(Encoding.UTF8.GetBytes(currentTypeMap)));
                        while (reader.Read())
                        {
                            // we find an opening xml element of collection type (bag/set/list). We hope to find an X-to-many element within.
                            if (_CollectionElementsToTypes.Keys.Contains(reader.Name) && reader.NodeType == XmlNodeType.Element && reader.GetAttribute(CollectionTypeXmlAttribute) == null)
                            {
                                string elementName = reader.Name; // we store the current element name to later see if we find a matching close element.
                                int lineNumber = reader.LineNumber - 1;// LineNumber property is 1 based. we want to use 0 based arrays.

                                while (reader.Read())
                                {
                                    if (reader.Name == elementName && reader.NodeType == XmlNodeType.EndElement) // we found the closing element for the collection.
                                        break;

                                    // we found an opening relation element (X-to-many) with a "class" attribute defined 
                                    // note: the "class" attribute tells us what type the elements of the collection will be.
                                    string classNameAttribute = reader.GetAttribute(ClassXmlAttribute);
                                    if (RelationsXmlElements.Contains(reader.Name) && reader.NodeType == XmlNodeType.Element && classNameAttribute != null)
                                    {
                                        Type collectionItemType = Type.GetType(classNameAttribute);
                                        string attributeValue = _CollectionElementsToTypes[elementName].MakeGenericType(collectionItemType).ToString();
                                        attributeValue = attributeValue.Replace(collectionItemType.FullName, string.Format("{0}, {1}", collectionItemType.FullName, collectionItemType.Assembly.GetName().Name));
                                        attributeValue = attributeValue + ", " + Assembly.GetExecutingAssembly().GetName().Name;

                                        string[] lines = currentTypeMap.Split(new string[] { System.Environment.NewLine }, StringSplitOptions.None);

                                        attributeValue = lines[lineNumber].Insert(lines[lineNumber].LastIndexOf(" "), string.Format(@" {0}=""{1}""", CollectionTypeXmlAttribute, attributeValue));

                                        currentTypeMap = currentTypeMap.Replace(lines[lineNumber], attributeValue);
                                    }
                                }
                            }
                        }

                        // because we want to offer the ObservableObject's functionality (I.E. property notifications and commands)
                        // we want to make sure that the mappings use the overriden type constructed by ObservableObject 
                        // instead of their base class counterparts.
                        foreach (KeyValuePair<Type, Type> mappedClass in _MappedClasses)
                        {
                            // NHibernate mappings sometimes allows specifying a type name without an assembly name. Therefore we
                            // want to make sure that we first replace the assembly qualified type name, and then the
                            // simple type name afterwards to avoid partial matches.
                            if (mappedClass.Key != currentType)
                            {
                                string assemblyQualifiedTypeName = string.Format(@"""{0}, {1}""", mappedClass.Key.FullName, mappedClass.Key.Assembly.GetName().Name);
                                if (currentTypeMap.Contains(assemblyQualifiedTypeName))
                                    currentTypeMap = currentTypeMap.Replace(assemblyQualifiedTypeName, string.Format(@"""{0}, {1}""", mappedClass.Value.FullName, mappedClass.Value.Assembly.GetName().Name));

                                string typeName = string.Format(@"""{0}""", mappedClass.Key.FullName);
                                if (currentTypeMap.Contains(typeName))
                                    currentTypeMap = currentTypeMap.Replace(typeName, string.Format(@"""{0}""", mappedClass.Value.FullName));
                            }
                        }

                        
                        // Create mappings for overriden type (they are exactly the same as the base type, but we just have to make sure to change the class name)
                        string className = string.Format(@"class name=""{0}, {1}""", currentType.FullName, currentType.Assembly.GetName().Name);
                        string overridenClassName = string.Format(@"class name=""{0}, {1}""", overridenType.FullName, overridenType.Assembly.GetName().Name);
                        string overridenTypeMap = currentTypeMap.Replace(className, overridenClassName);

                        // add type maps to NHibernate configuration
                        Configuration.AddInputStream(new MemoryStream(Encoding.UTF8.GetBytes(currentTypeMap)));
                        Configuration.AddInputStream(new MemoryStream(Encoding.UTF8.GetBytes(overridenTypeMap)));
                    }
                }
            }
        }
}

There are three important functons that the NHibernateHelper class must perform.
First, the NHibernateHelper class is in charge of generating mappings for the derived objects that are created by the ObservableObject class. Without these maps NHibernate would not be able to load any data onto our objects.
Second, it is in charge of replacing reference to custom types (types created by the end developer) with references to their derived types. In other words, we want to tell NHibernate to construct and load an object derived of the defined class so that we have the nice property changed and commands functionality provided by ObservableObject<T>.
Third, we also want to ensure that collections on the objects have notifications (so that they play nicely with WPF). Which brings me to the next section.



Collections


When designing types, it is quite likely that you are going to define collections just as frequently as single-object properties. Since WPF requires collections to implement INotifyCollectionChanged for binding purposes, we have to come up with a custom collection (or a set of custom collections in this case) that implements INotifyCollectionChanged and it is also able to persist itself using the NHibernate engine by inheriting PersistentGenericBag<T> or PersistentGenericSet<T>.


[Serializable]
public class DatabaseCollection<T> : PersistentGenericBag<T>, INotifyCollectionChanged 
{
 public event NotifyCollectionChangedEventHandler CollectionChanged;

 public DatabaseCollection(ISessionImplementor session) : base(session) { }

 public DatabaseCollection(ISessionImplementor session, ICollection<T> coll) : base(session, coll)
 {

  if (coll != null)
   ((INotifyCollectionChanged)coll).CollectionChanged += OnCollectionChanged;
        }

 public override void BeforeInitialize(ICollectionPersister persister, int anticipatedSize)
 {
  base.BeforeInitialize(persister, anticipatedSize);
  ((INotifyCollectionChanged)InternalBag).CollectionChanged += OnCollectionChanged;
 }

 protected void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
 {
  if (CollectionChanged != null)
   CollectionChanged(this, args);
 }
}

[Serializable]
public class DatabaseSet<T> : PersistentGenericSet<T>, INotifyCollectionChanged
{
 public event NotifyCollectionChangedEventHandler CollectionChanged;

 public DatabaseSet(ISessionImplementor session) : base(session) { }

 public DatabaseSet(ISessionImplementor session, ISet<T> coll) : base(session, coll)
 {
  if (coll != null)
   ((INotifyCollectionChanged)coll).CollectionChanged += OnCollectionChanged;
        }

 public override void BeforeInitialize(ICollectionPersister persister, int anticipatedSize)
 {
  base.BeforeInitialize(persister, anticipatedSize);
   ((INotifyCollectionChanged)gset).CollectionChanged += OnCollectionChanged;
 }

 protected void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
 {
  if (CollectionChanged != null) 
   CollectionChanged(this, args);
 }
}

When designing your types, you should use a DatabaseCollection<T> or DatabaseSet<T> as collection types, and in addition to getting collection notifications, thanks to the magic happening in NHibernateHelper you will automatically get items that implement INotifyPropertyChanged and have ICommands for all their methods.



DatabaseCollection Extensions


It wouldn't be object-oriented design if you weren't able to call a Load or a Save method straight from a collection and get the expected functionality from it. Thanks to the nice Extension Methods feature of the .Net framework 3.5 we can do just that not only for the DatabaseCollection<T> and DatabaseSet<T> but also for any collection type that implements ICollection<T>.


public static class DatabaseCollectionEx
    {
        public static void Save<T>(this ICollection<T> collection)
        {
            ISession session = NHibernateHelper.Configuration.BuildSessionFactory().OpenSession();
            foreach (var o in collection)
                session.SaveOrUpdate(o);
            session.Flush();
            session.Close();
        }

        public static void Load<T>(this ICollection<T> collection)
        {
            ISession session = NHibernateHelper.Configuration.BuildSessionFactory().OpenSession();
            foreach (T item in session.CreateCriteria(ObservableObject<T>.CreateOverridenType()).List())
                collection.Add(item);
            session.Flush();
            session.Close();
        }

        public static void Load<T>(this ICollection<T> collection, params ICriterion[] criteria)
        {
            ISession session = NHibernateHelper.Configuration.BuildSessionFactory().OpenSession();
            ICriteria c = session.CreateCriteria(ObservableObject<T>.CreateOverridenType());
            foreach (ICriterion criterion in criteria)
                c = c.Add(criterion);
            foreach (T item in c.List<T>())
                collection.Add(item);
            session.Flush();
            session.Close();
        }
    }

As you can see, besides saving content of a collection you can also load the contents of an entire table or a reduced subset by passing criteria to the Load method.


Here is a couple of sample business objects:


[Class(Name = "AndresLook.Address, AndresLook", Lazy = false, Table = "Address")]
    public abstract class Address : DatabaseObject<address>
{
        [Id(0, Name = "AddressId", Column = "AddressId")]
        [Generator(1, Class = "identity")]
        public virtual int AddressId { get; set; }
        [Property(Column = "ContactId")]
        public virtual int ContactId { get; set; }
        [Property(Column = "Address1")]
        public virtual string Address1 { get; set; }
    }

[Class(Name="AndresLook.Contact, AndresLook", Lazy=false, Table="Contact")]
    public abstract class Contact : DatabaseObject<contact>
    {
        [Id(0, Name="ContactId", Column="ContactId")]
        [Generator(1, Class = "identity")]
        public virtual int ContactId { get; set; }

        [Property(Column="FirstName")]
        public virtual string FirstName { get; set; }

        [Property(Column="LastName")]
        public virtual string LastName { get; set; }

        [Bag(0, Name = "Addresses", Table = "Address", Lazy = CollectionLazy.False, Cascade = "save-update")]
        [Key(1, Column = "ContactId")]
        [Index(2, Column="AddressId")]
        [OneToMany(3, Class = "AndresLook.Address, AndresLook")]
        public virtual IList<address>
Addresses { get; set; }

        public Contact()
        {
            // We define "Addresses" as an observablecollection by default
            // if we instantiate Contact using the .New() method we should be able
            // to add entries to Addresses and using the .Save() method should
            // save those entries to the database as expected.
            Addresses = new ObservableCollection<address>();
        }
    }

And here is how you can tap onto the databse functionality:


Contact c = Contact.New();
c.Load(1);

List<address>
a = new List<address>();
a.Load(NHibernate.Criterion.Expression.Eq("AddressId", 1));

In my next article, I'll demonstrate how to create a CommunicationObject that transfer data from a server to a client and vice versa.






Tuesday, January 5, 2010

MultiuseModel-View (MMV) Object modeling pattern with WPF and WCF: The Foundation



Download sample ObservableObject project



In my previous article I went over how to break up a multiuse object into logical parts. In this article I will talk about an ObservableObject: an object that notifies WPF of changes.



The ObservableObject Class


There are two type of members that you can bind in a WPF app: properties and methods. Requirements for binding properties is fairly straight forward: one must implement INotifyPropertyChanged. To bind a method, on the other hand, we must actually have a property of type ICommand for each method we want to bind to.


Implementing INotifyPropertyChanged simply consists of raising the PropertyChanged event every time a property changes. The problem lies in making a child class of ObservableObject to raise the event without having the developer of the child class call it himself/herself. The best solution for this problem is to use Reflection.Emit to construct a child class of the templated class and override the properties' set method to raise the event after executing the template's set method logic.


foreach (PropertyInfo property in parentType.GetProperties())
                {
                    method = parentType.GetMethod("set_" + property.Name);
                    methodBuilder = typeBuilder.DefineMethod(method.Name, method.Attributes, method.ReturnType, method.GetParameters().Select(pi => pi.ParameterType).ToArray());
                    il = methodBuilder.GetILGenerator();
                    locAi = il.DeclareLocal(typeof(ArgIterator));

                    il.Emit(OpCodes.Nop);
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldarg_1);
                    il.EmitCall(OpCodes.Call, method, null);
                    il.Emit(OpCodes.Nop);
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldstr, property.Name);
                    il.EmitCall(OpCodes.Call, parentType.GetMethod("OnPropertyChange", BindingFlags.NonPublic | BindingFlags.Instance), null);
                    il.Emit(OpCodes.Nop);
                    il.Emit(OpCodes.Ret);
                    typeBuilder.DefineMethodOverride(methodBuilder, method);
                }

With this in mind, adding ICommands for methods becomes just as easy: we can use the same TypeBuilder to add new properties of type ICommand for each public method.



foreach (MethodInfo mi in parentType.GetMethods(BindingFlags.Instance | BindingFlags.Public).Where(methodInfo => !methodInfo.Name.StartsWith("get_") && !methodInfo.Name.StartsWith("set_") && !methodInfo.Name.StartsWith("add_") && !methodInfo.Name.StartsWith("remove_")))
                {
                    FieldBuilder commandField = typeBuilder.DefineField("_" + mi.Name + cExtendedTypesCommandPostfix, typeof(DelegateCommand), FieldAttributes.Private);

                    MethodBuilder commandGetMethod = typeBuilder.DefineMethod("get_" + mi.Name + cExtendedTypesCommandPostfix, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(ICommand), Type.EmptyTypes);
                    ILGenerator commandGetMethodIL = commandGetMethod.GetILGenerator();

                    var commandNullLabel = commandGetMethodIL.DefineLabel();
                    var defaultLabel = commandGetMethodIL.DefineLabel();

                    commandGetMethodIL.Emit(OpCodes.Nop);
                    commandGetMethodIL.Emit(OpCodes.Ldarg_0);
                    commandGetMethodIL.Emit(OpCodes.Ldfld, commandField);
                    commandGetMethodIL.Emit(OpCodes.Ldnull);
                    commandGetMethodIL.Emit(OpCodes.Ceq);
                    commandGetMethodIL.Emit(OpCodes.Brfalse, commandNullLabel);
                    commandGetMethodIL.Emit(OpCodes.Ldarg_0);
                    commandGetMethodIL.Emit(OpCodes.Ldarg_0);
                    commandGetMethodIL.Emit(OpCodes.Ldftn, mi);
                    commandGetMethodIL.Emit(OpCodes.Newobj, typeof(Action).GetConstructor(new Type[] { typeof(object), typeof(IntPtr) }));
                    commandGetMethodIL.Emit(OpCodes.Newobj, typeof(DelegateCommand).GetConstructor(new Type[] { typeof(Action) }));
                    commandGetMethodIL.Emit(OpCodes.Stfld, commandField);
                    commandGetMethodIL.MarkLabel(commandNullLabel);
                    commandGetMethodIL.Emit(OpCodes.Ldarg_0);
                    commandGetMethodIL.Emit(OpCodes.Ldfld, commandField);
                    commandGetMethodIL.Emit(OpCodes.Ret);

                    PropertyBuilder commandProperty = typeBuilder.DefineProperty(mi.Name + cExtendedTypesCommandPostfix, PropertyAttributes.HasDefault, typeof(ICommand), null);
                    commandProperty.SetGetMethod(commandGetMethod);
                }

Now for all of this to work we need to make sure two things happen: first the consumer of the template object should actually get an instance of the derived type. And second, since the consumer is actually using a child class of the type he/she declared, we must ensure that reflection and typing compatibility is achieved. To do this, we must first of all provide a means of instantiating a new object (with a New() static method) and we must also override the GetType() of the child type we have created to return an instance of the template's Type class.


MethodInfo method = typeof(object).GetMethod("GetType", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { }, null);
                MethodBuilder methodBuilder = typeBuilder.DefineMethod(method.Name, method.Attributes, typeof(Type), method.GetParameters().Select(pi => pi.ParameterType).ToArray());
                ILGenerator il = methodBuilder.GetILGenerator();
                LocalBuilder locAi = il.DeclareLocal(typeof(ArgIterator));

                il.Emit(OpCodes.Ldtoken, parentType);
                il.EmitCall(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Public | BindingFlags.Static), null);
                il.Emit(OpCodes.Stloc_0);
                il.Emit(OpCodes.Ldloc_0);
                il.Emit(OpCodes.Ret);

public static T New()
        {
            return ((T)Activator.CreateInstance(CreateOverridenType(typeof(T))));
        }

In my next article, I'll demonstrate how to create an enterprise level DatabaseObject and DatabaseCollection classes.




Monday, January 4, 2010

MultiuseModel-View (MMV) Object modeling pattern with WPF and WCF: Genesis



In my previous article I gave a basic introduction to the Multiuse-Model View pattern. In this short article I will explain in detail the concepts behind a MMV library.



The Multiuse-Object Theory


A well organized framework is highly dependent on inheritance and encapsulation to avoid messy code and unnecessary overhead. Let's take the WPF framework itself for instance: when you are dealing with controls... say... a Button, you are dealing with a class that inherits from DispatcherObject, DependencyObject, Visual, UIElement, FrameworkElement, Control, ContentControl and ButtonBase. Each of these parent classes provide a different piece of functionality to their children such that by the time we get to deal with the Button class, we only have to worry about a few methods and properties to make the button show up on the screen and display text (or other stuff) inside and handle user events.
Likewise, with our Multiuse-Model approach, we want a set of classes that provide basic functionality to our business objects in order to encapsulate operations related to databases, client-server communications and even property notification changes.
In my previous article I wrote about lumping all this functionality in one single class, the MultiuseObject class, however, for large scale applications this would be cumbersome since the amount of functionality in a realistic framework is excessive for a single class. For this reason it is better to slice and dice each set of functionality into their own classes. At a minimum you should have the following classes as parents of your business objects:


  • ObservableObject: provides implementation of INotifyPropertyChanged for properties and ICommands for methods.
  • DatabaseObject: provides functionality to retrieve and store information on a database (there are many good data-layer libraries already, this object would wrap their functionality).
  • CommunicationObject: provides client-server communications.
  • MultiuseObject: wraps all functionality in a nice and neat package.

These classes are listed in order of inheritance, since, it is likely that sometimes you might not need to deal with the entire functionality. For example, sometimes you will have UI-only objects that would inherit straight from ObservableObject opposed to MultiuseObject.

In my next article, I'll demonstrate how to create an enterprise level ObservableObject class.



Thursday, October 8, 2009

MultiuseModel-View (MMV) Object modeling pattern with WPF and WCF: Is MVVM the antichrist?


Download sample MVVM project
Download sample MMV project


In today's world of WPF and WCF client-server applications, MVVM has been growing in popularity among multi-tier app developers. In this series of articles, I will discuss why I think MVVM is an abomination to object oriented programming and I will demonstrate a different way in which developers can write applications.

Model View ViewModel

To understand why MVVM is not the best way to go, we must first understand what MVVM is and how it works. For a more detailed description about MVVM see the Model View ViewModel Design Pattern for WPF.

MVVM consists basically of having a set of classes that define your data, a set of classes that define your behavior and a set of classes that define your looks and feel.

Let's take a simple address book application as an example:


Let's assume the application will use the following database table as the persistence storage:


In a typical WPF/WCF application you would likely have a project that contains your Data Object Model, another project that contain your Data Transport Object Model and converters between the data objects and the DTO objects, a project that contains your View Model and converters between the DTO objects and the VM objects and another project that contains your Views. Implementations might vary slightly across projects and developers, but for the most part a typical address book application might look like this:


Notice that we have 3 classes that are a representation of the data stored in the contact table (Contact, ContactDTO, and ContactViewModel). All these classes expose more or less the same number of properties, with the difference that the ContactDO class has logic pertaining to the database (most likely a map if you use NHibernate) ContactDTO is a (most likely SOAP) serializable object, and ContactVM contains ICommands and other view-related properties.

When I see this, what immediately pops to mind is my programming 201 class back in college: fundamentals of programming, when we talked about the four basic principles of object oriented programming (for those of you who don't remember, they are: Encapsulation, Abstraction, Inheritance, and Polymorphism). I don't know about you but I certainly don't see any of these principles being applied in the MVVM pattern. We have 3 classes that do almost the same thing (there goes Encapsulation), they are not tied together whatsoever (tough luck Abstraction), they do not share their properties with each other (oops - too bad Inheritance) they are not swappable in different contexts (Polymorphism). So what's the big deal? you might ask. if you ever worked on an MVVM application I'm sure you've noticed (as I have) that adding a new piece of data (property) or functionality (methods, classes, etc) to an existing object model is a huge pain in the ass, time consuming, cumbersome and most importantly there is a high chance of forgetting something and producing faulty code.Think about it: if you want to add 1 column to our database table you would have to change at least 5 classes (sometimes more depending on the project). The chances of forgetting something or screwing something up are 500% higher than if you only had 1 class to worry about. Not to mention 5 times the amount of time it'll take to make the change (not counting time spending debugging the errors caused by what you forgot to change).

To summarize, here is a list of Pros and Cons for MVVM:

Pros:

  • Hard separation between logic (view model) and display (view).
  • Easy to unit test UI logic.
  • Leverages WPF technologies such as binding and commanding.

Cons:

  • Does not conform to Object Oriented Programming standards.
  • It is too complex for simple UI operations.
  • For large applications it requires a large amount of metadata generation.
  • Requires duplication of code.
  • It is complex to maintain.

The Multiuse-Model View approach

So we know that MVVM is quite the opposite of what we want as object oriented developers, it is hard to maintain, and requires duplication of code. But the question is: what IS a feasible object oriented solution to this problem? the answer is MMV: a pattern that uses Encapsulation, Abstraction, Inheritance, and Polymorphism to transport data all the way from the database to the view.

Let's take our Address Book example one more time. Given the same contact table, let's draw a new solution:


Woha, what happened to all the projects? now we have 6 projects instead of 7 but only 1 class that represents the contact table. We still have a public and a private web server, we have the very same shell application and the very same view as in the MVVM pattern, but we now have 1 project for the entire data model (plus one “core” project that we will get to later). So let's take a closer look at the Contact class:

[Table(Name="Contact_tbl")]
public class Contact : MultiuseObject<Contact>
{
 public virtual int ContactId { get; set; }
 public virtual string FirstName { get; set; }
 public virtual string LastName { get; set; }
 public virtual string Email { get; set; }

 public void SendEMail()
 {
  Process.Start(string.Format("mailto:{0}", Email));
 }
}

This is a simple class with 4 properties and a method to perform some action particular to a contact (in this case, from an object model point of view, we want to be able to send emais to the contacts in our database). A couple of things pop right out by simply glancing at this:

  • First of all we see the TableAttribute for the class. For the time being ignore this since it is specific to retrieving data from the database. This might not be necessary depending on the flavor of persistence library that you like the most (for example, if you use NHibernate you would have either a mapping class or an XML file).
  • Second, we notice that all of our relevant properties as declared as virtual. This ties to our third point.
  • Third, this class inherits from a generic MultiuseObject class (where all the magic happens).

Notice how much cleaner and simpler to read this one class (that encapsulates everything you need) is. If you wanted to add or remove a column from the database, all you would have to do is to add a corresponding property to this class and viola! You’re done; the MultiuseObject class takes care of getting and saving the object from the database, it takes care of sending objects and collections of objects from the private server to the public server and from the public server to the client, and it even implements INotifyPropertyChanged and creates ICommands for you. How does it do all of this? Well, let’s take a look at our sample MultiuseObject<t> class:

public abstract class MultiuseObject<T> : INotifyPropertyChanged
{
    private const string cExtendedTypesAssemblyName = "MMV.ExtendedTypes";
    private const string cExtendedTypesModuleName = "MMV.ExtendedTypes";
    private const string cExtendedTypesNamePostfix= "<>Extended";
    private const string cExtendedTypesCommandPostfix = "Command";

    // every time the CLR loads a type derived from MultiuseObject, we'll create a new type that adds needed features for WPF (such as NotifyPropertyChanged and Commands)
    static MultiuseObject()
    {
        CreateOverridenType(typeof(T));
        // this is to ensure that the newly created assembly gets properly loaded by WCF's DataContractSerializer on deserialization.
        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { return(GetExtendedTypesAssembly()); };
    }

    #region INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChange(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion


    /// <summary>
    /// provides functionality to derived objects to get all data related to the type from the database.
    /// </summary>
    public static List<T> GetAllFromDB()
    {
        List<T> returning = new List<T>();

        // note: here you can use any persistance library to dynamically populate a list of all objects
        using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["MMVSample"].ConnectionString))
        {
            connection.Open();
            using (SqlCommand command = new SqlCommand(string.Format("select * from {0}", ((TableAttribute)typeof(T).GetCustomAttributes(typeof(TableAttribute), true)[0]).Name), connection))
            {
                SqlDataReader reader = command.ExecuteReader();
                while (reader.Read())
                {
                    // the trick here is to return an instance of the dynamically derived type.
                    T c = (T)Activator.CreateInstance(CreateOverridenType(typeof(T))); 
                    for (int i = 0; i < reader.FieldCount; i++)
                    {
                        object value = reader.GetValue(i);
                        if (!(value is DBNull))
                            typeof(T).GetProperty(reader.GetName(i)).SetValue(c, value, null);
                    }
                    returning.Add(c);
                }
            }
        }
        return (returning);
    }

    /// <summary>
    /// provides functionality to derived objects to call GetAllObjectsFromDB from a client app with 
    /// no access to the database. (for example, the public server)
    /// </summary>
    public static List<T> GetAllFromPrivateServer()
    {
        ServiceClient<IMultiuseObjectPrivateServiceContract> client = new ServiceClient<IMultiuseObjectPrivateServiceContract>();
        return (client.ContractChannel.GetAll(typeof(T)).Cast<T>().ToList());
    }

    /// <summary>
    /// provides functionality to derived objects to call GetAllObjectsFromDB from a client app with 
    /// no access to the database and no access to the private server. (for example, the WPF client app)
    /// </summary>
    public static List<T> GetAllFromPublicServer()
    {
        ServiceClient<IMultiuseObjectPublicServiceContract> client = new ServiceClient<IMultiuseObjectPublicServiceContract>();
        return (client.ContractChannel.GetAll(typeof(T)).Cast<T>().ToList());
    }

    /// <summary>
    /// Looks for or creates a new AssemblyBuilder and a corresponding module to store our dynamically derived types.
    /// </summary>
    private static AssemblyBuilder GetExtendedTypesAssembly()
    {
        var assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(a => a.FullName.Contains(cExtendedTypesAssemblyName));
        if (assemblies.Count() > 0)
            return ((AssemblyBuilder)assemblies.First());
        else
        {
            AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName() { Name = cExtendedTypesAssemblyName }, AssemblyBuilderAccess.RunAndSave);
            assemblyBuilder.DefineDynamicModule(cExtendedTypesModuleName, true);
            return (assemblyBuilder);
        }
    }

    /// <summary>
    /// This is the key method for encapsulating WPF functionality without redundancy. This method overrides virtual properties to call
    /// NotifyPropertyChanged, it creates ICommands for public methods, and it shadows the GetType method for serialization compatibility.
    /// </summary>
    private static Type CreateOverridenType(Type parentType)
    {
        string childTypeName = parentType.Namespace + "." + parentType.Name + cExtendedTypesNamePostfix;

        AssemblyBuilder assemblyBuilder = GetExtendedTypesAssembly();
        ModuleBuilder moduleBuilder = assemblyBuilder.GetDynamicModule(cExtendedTypesModuleName);

        Type childType = moduleBuilder.GetType(childTypeName);
        if (childType == null)
        {
            TypeBuilder typeBuilder = moduleBuilder.DefineType(childTypeName, parentType.Attributes, parentType);

            // shadow GetType
            // some serializers (DataContractSerializer for example) use
            // GetType to validate if the deserialized type is the same as
            // the alleged return type. If they are not equal they thrown an exception.
            // to bypass this we override GetType to return the value of the base type.
            MethodInfo method = typeof(object).GetMethod("GetType", BindingFlags.Public | BindingFlags.Instance , null, new Type[] { }, null);
            MethodBuilder methodBuilder = typeBuilder.DefineMethod(method.Name, method.Attributes, typeof(Type), method.GetParameters().Select(pi => pi.ParameterType).ToArray());
            ILGenerator il = methodBuilder.GetILGenerator();
            LocalBuilder locAi = il.DeclareLocal(typeof(ArgIterator));

            il.Emit(OpCodes.Ldtoken, parentType);
            il.EmitCall(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Public | BindingFlags.Static), null);
            il.Emit(OpCodes.Stloc_0);
            il.Emit(OpCodes.Ldloc_0);
            il.Emit(OpCodes.Ret);

            // we create an ICommand property and a backing DelegateCommand field for each public method (we exclude backing methods for properties and events).
            foreach (MethodInfo mi in parentType.GetMethods(BindingFlags.Instance | BindingFlags.Public).Where(methodInfo => !methodInfo.Name.StartsWith("get_") && !methodInfo.Name.StartsWith("set_") && !methodInfo.Name.StartsWith("add_") && !methodInfo.Name.StartsWith("remove_")))
            {
                FieldBuilder commandField = typeBuilder.DefineField("_" + mi.Name + cExtendedTypesCommandPostfix, typeof(DelegateCommand), FieldAttributes.Private);

                MethodBuilder commandGetMethod = typeBuilder.DefineMethod("get_" + mi.Name + cExtendedTypesCommandPostfix, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(ICommand), Type.EmptyTypes);
                ILGenerator commandGetMethodIL = commandGetMethod.GetILGenerator();

                var commandNullLabel = commandGetMethodIL.DefineLabel();
                var defaultLabel = commandGetMethodIL.DefineLabel();

                commandGetMethodIL.Emit(OpCodes.Nop);
                commandGetMethodIL.Emit(OpCodes.Ldarg_0);
                commandGetMethodIL.Emit(OpCodes.Ldfld, commandField);
                commandGetMethodIL.Emit(OpCodes.Ldnull);
                commandGetMethodIL.Emit(OpCodes.Ceq);
                commandGetMethodIL.Emit(OpCodes.Brfalse, commandNullLabel);
                commandGetMethodIL.Emit(OpCodes.Ldarg_0);
                commandGetMethodIL.Emit(OpCodes.Ldarg_0);
                commandGetMethodIL.Emit(OpCodes.Ldftn, mi);
                commandGetMethodIL.Emit(OpCodes.Newobj, typeof(Action).GetConstructor(new Type[] { typeof(object), typeof(IntPtr) }));
                commandGetMethodIL.Emit(OpCodes.Newobj, typeof(DelegateCommand).GetConstructor(new Type[] { typeof(Action) }));
                commandGetMethodIL.Emit(OpCodes.Stfld, commandField);
                commandGetMethodIL.MarkLabel(commandNullLabel);
                commandGetMethodIL.Emit(OpCodes.Ldarg_0);
                commandGetMethodIL.Emit(OpCodes.Ldfld, commandField);
                commandGetMethodIL.Emit(OpCodes.Ret);

                PropertyBuilder commandProperty = typeBuilder.DefineProperty(mi.Name + cExtendedTypesCommandPostfix, PropertyAttributes.HasDefault, typeof(ICommand), null);
                commandProperty.SetGetMethod(commandGetMethod);
            }

            // we override the virtual properties to call OnPropertyChanged after calling the base class implementation.
            foreach (PropertyInfo property in parentType.GetProperties())
            {
                method = parentType.GetMethod("set_" + property.Name);
                methodBuilder = typeBuilder.DefineMethod(method.Name, method.Attributes, method.ReturnType, method.GetParameters().Select(pi => pi.ParameterType).ToArray());
                il = methodBuilder.GetILGenerator();
                locAi = il.DeclareLocal(typeof(ArgIterator));

                il.Emit(OpCodes.Nop);
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldarg_1);
                il.EmitCall(OpCodes.Call, method, null);
                il.Emit(OpCodes.Nop);
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldstr, property.Name);
                il.EmitCall(OpCodes.Call, parentType.GetMethod("OnPropertyChange", BindingFlags.NonPublic | BindingFlags.Instance), null);
                il.Emit(OpCodes.Nop);
                il.Emit(OpCodes.Ret);
                typeBuilder.DefineMethodOverride(methodBuilder, method);
            }
            childType = typeBuilder.CreateType();
        }
        return (childType);
    }
}

To use a multiuse object, we can simply call one of its methods from the appropriate application level. For example, to bind the main view of our contact application we call the Contact class as such:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
  
        MainView mv = new MainView();
        mv.DataContext = Contact.GetAllFromPublicServer();
        mv.Show();
    }
}

This is what the public server will do in turn:

public class AddressBookDataService : IMultiuseObjectPublicServiceContract
{
    public List<object> GetAll(Type returnObjectType)
    {
        return ((IEnumerable)returnObjectType.GetMethod("GetAllFromPrivateServer", BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy).Invoke(null, null)).Cast<object>().ToList();
    }
}

And the private server will call the GetAllFromDB method like this:

public class AddressBookDataService : IMultiuseObjectPrivateServiceContract
{
    public List<object> GetAll(Type returnObjectType)
    {
        return ((IEnumerable)returnObjectType.GetMethod("GetAllFromDB", BindingFlags.Static  BindingFlags.Public  BindingFlags.FlattenHierarchy).Invoke(null, null)).Cast<object>().ToList();
    }
}

If we want to add more functionality to our multiuse objects, all we have to do is implement the desired behavior in the MultiuseObject class and modify the IMultiuseObjectServiceContract accordingly:

[ServiceContract]
public interface IMultiuseObjectServiceContract
{
    [OperationContract]
    List<object> GetAll(Type returnObjectType);
}

As you can see, we can use the same WPF View that you would normally use on an MVVM app but with a cleaner and nicer object model behind it.

To recap, the Pros and Cons of MMV are as follows:

Pros:

  • Hard separation between logic (view model) and display (view).
  • Easy to unit test UI logic.- Leverages WPF technologies such as binding and commanding.
  • Conforms to Object Oriented Programming standards.
  • Requires minimum amount of code to extend.
  • It is easy to maintain.

Cons:

  • Requires a complex core library.
  • Requires the application stack to be all Microsoft-based products. (it is obviously not compatible with Java or other server-side technologies)

In my next article I'll demonstrate how to create an extensive MultiuseObject core Library.