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!!





No comments:

Post a Comment