Being serious about the command table pattern.

Introduction

Although the command table pattern is not an official design pattern, it is quite known in the LightSwitch development community. It should not be confused with the Command Pattern, which is basically the pattern for managing commands (implementing the ICommand interface) in an MVVM context.

What is the Command table pattern

In a typical LightSwitch project, the communication between client and server is about

  1. querying data adhering to the tabular structure of an entity and
  2. commanding applied on entities known in the domain model and restricted to inserts, deletes and updates.
So, a simple method invocation from client to serve can not take place without the help of an entity know in the domain model serving as communication medium. The usage of such a command table with the sole purpose of sending a request for a method invocation to the server is the command table pattern.

A Quick and dirty command table pattern implementation

So, imagine we want to send from client to server a message to start the generation of a report server side. We will not bother here about the details of the report generation, but just focus on the invocation mechanism.

First of all we need a table for carrying our message. Let’s call this table “ServerCommand”. It will carry a field called “verb” and a series of parameters fields (all of type string).

Client side we put a button somewhere on a screen where we call the code to create such a ServerCommand.

public partial class CustomersListDetail
    {
        partial void GenerateReportServerSide_Execute()
        {
            var ws = this.Application.CreateDataWorkspace();
            ServerCommand command = ws.ApplicationData.ServerCommands.AddNew();
            command.Verb = "CreateServerReport";
            command.Param1 = DateTime.Now.Date.ToString();
            command.Param2 = "34";
            ws.ApplicationData.SaveChanges();

        }
    }

Server side we need to handle the incoming command:

partial void ServerCommands_Inserting(ServerCommand entity)
        {
            switch (entity.Verb)
            {
                case "CreateServerReport":
                    CreateReport(entity.Param1, entity.Param2);
                    break;

                default:
                    break;
            }
        }

So, the idea is pretty simple: we send a servercommand entity to the server and the server will, as kind of “side-effect” processing during the insert of the serverCommand record, start the generation of our report.

On what do we need improvement?

Well, if your application has only one or just a few commands in the whole application, you should definitely stick to the above approach, unless you want to over engineer things.

But in the scenario where commanding takes a prominent place in your application, it makes sense to try to improve the above approach.  Why?

  • the most problematic point is the handling of command parameters both on the level of amount of parameters and on the level of parameter types.
  • The basic command table contains 3 standard parameters which might be ok for our first command, but maybe tomorrow we have a command that requires 4 parameters.
  • All command parameters are supposed to be of type string. That can make things rather error prone. We need to be sure we handle conversions to e.g. dates correctly, that we take care of language/culture correctly during conversion, etc. …
  • what about the application security of our commanding system? If we have several command in our app, it could be very practical if the servercommand could leverage  the build-in permission mechanism of LightSwitch.
  • what about exception handling during the command execution ?
As a result, it is clear we need a base infrastructure which can deal with this.

An implementation with some base infrastructure

The ServerCommand Entity

Let’s design a new ServerCommand entity taking the following structure:

As you can see we still have the verb field, used for informing the server which command to execute. We also specify a ParameterClassName. this reveals that we will use a class structure to organise the set of parameters that belong to a command. The SerializedParameters field will carry the eventual parameters (based on the parameter class) as a serialized string. the KeepCommandEntry boolean field will indicate if the server command record should be kept or not. The response field can carry response information from the server.

The parameter serialization mechanism.

Client side we will need a method which can serialize the command parameters:

 public static  class ClientCommandHelper
    {
        public static string Serialize<T>(T entity)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            using (MemoryStream stream = new MemoryStream())
            {
                serializer.Serialize(stream, entity);
                stream.Seek(0, SeekOrigin.Begin);

                using (StreamReader reader = new StreamReader(stream))
                {
                    return reader.ReadToEnd();
                }
            }
        }
    }

So, a client command that be easily created:

private void TriggerPersonCommand()
        {
            var dataWorkspace = this.Application.CreateDataWorkspace();
            ServerCommand c = dataWorkspace.ApplicationData.ServerCommands.AddNew();
            c.Verb = AvailableServerCommands.PersonCommand ;
            c.KeepCommandEntry = true;
            c.ParameterClassName = typeof(PersonCommandParameters).Name;

            PersonCommandParameters commandParameters = new PersonCommandParameters() { FirstName = "paul", LastName = "van bladel" };
            c.SerializedParameters = ClientCommandHelper.Serialize(commandParameters);
            dataWorkspace.ApplicationData.SaveChanges();
        }

We make use here of the following simple parameter class:

 public class PersonCommandParameters
    {
        public string LastName { get; set; }
        public string FirstName { get; set; }
    }

We store the above class in the common project in such a way it is also available from the server project.

The above uses also a very simple class (again present in the common project) for storing the list of potential commands:

 public static class AvailableServerCommands
    {
        public const string PersonCommand = "PersonCommand";
    }

The Server side command handling engine

The server side handling is a bit more involved.

The main entry point for the command handling mechanism is of course the ServerCommands_Inserting method.

public partial class ApplicationDataService
    {
        partial void ServerCommands_Inserting(ServerCommand entity)
        {
           ServerCommandHelper.TriggerCommand(entity);
        }
    }

As you can see, we dispatch the whole handling to the TriggerCommand method.

 class ServerCommandHelper
    {
        public static void TriggerCommand<C>(C entity) where C : IEntityObject, IServerCommand
        {
            Type commandType = Type.GetType("LightSwitchApplication." + entity.Details.Properties["Verb"].Value.ToString());
            if (commandType != null)
            {
                object instance = Activator.CreateInstance(commandType, entity);
                MethodInfo startMethod = commandType.GetMethod("StartExecution");
                startMethod.Invoke(instance, null);
            }
        }
    }

From this point onwards we are no longer depending on the ServerCommand table structure. In order to introduce this indirection, we use the IServerCommand interface:

public interface IServerCommand
    {
        bool KeepCommandEntry { get; set; }
        string Response { get; set; }
        string SerializedParameters { get; set; }
        string Verb { get; set; }
    }

So, we must make sure that the ServerCommand table implements this interfact:

public partial class ServerCommand : IServerCommand
    {
        //...

    }

As you can see, we use reflective code to start the command, so we don’t need a cumbersome switch statement here.

The actual PersonCommand which is triggered goes as follows:

public class PersonCommand : ServerCommandBase<ServerCommand>
    {
        public PersonCommand(ServerCommand serverCommand) : base(serverCommand) { }

        protected override void Execute()
        {
            PersonCommandParameters personCommandParameters = this.Parameters as PersonCommandParameters;
            Thread.Sleep(3000); //emulates running process  ---- do here sophisticated command handling.... (e.g. updating a batch of customers, generating a report...)
        }

        protected override void CanExecute(ref bool result)
        {
            result = Application.Current.User.HasPermission(Permissions.CanExecuteMyCommand);
        }

        protected override void ProvidePositiveResultMessage(ref string positiveResultMessage)
        {
            positiveResultMessage = "ok";
        }

        protected override void ProvideExceptionResultMessage(ref string exceptionResultMessage)
        {
            exceptionResultMessage = "we screwed it up";
        }
    }

The execute method is where it is all about. The command is derived from a base class ServerCommandBase, which contains the actual added value:

public abstract class ServerCommandBase<C> where C : IEntityObject, IServerCommand
    {
        protected Object Parameters;
        protected C ServerCommand;
        internal ServerCommandBase(C serverCommand)
        {
            bool canExecute = false;
            this.CanExecute(ref canExecute);
            if (canExecute == false)
            {
                string errorMessage = string.Format("The current user is not allowed to execute the command {0}", serverCommand.Details.Properties["Verb"].Value.ToString());
                throw new Exception(errorMessage);
            }

            ServerCommand = serverCommand;
        }

        public void StartExecution()
        {
            Parameters = DeserializeInstanceFromVerbName(ServerCommand);
            try
            {
                Execute();
                string positiveResultMessage = string.Empty;
                this.ProvidePositiveResultMessage(ref positiveResultMessage);

                ServerCommand.Details.Properties["Response"].Value = positiveResultMessage;
            }
            catch (Exception)
            {
                string exceptionResultMessage = string.Empty;
                this.ProvideExceptionResultMessage(ref exceptionResultMessage);
                ServerCommand.Details.Properties["Response"].Value = exceptionResultMessage;

                // it could make sense to dump the real exception in a log table. Sending the full exception details to the client is probably a bad practice
            }
            finally
            {
                if ((bool)ServerCommand.Details.Properties["KeepCommandEntry"].Value == false)
                {
                    ServerCommand.Details.DiscardChanges();
                }
            }
        }
        protected abstract void Execute();
        protected abstract void CanExecute(ref bool result);
        protected abstract void ProvidePositiveResultMessage(ref string positiveResultMessage);

        protected abstract void ProvideExceptionResultMessage(ref string exceptionResultMessage);

        private static object DeserializeInstanceFromVerbName(IEntityObject serverCommand)
        {
            Type t = CommonSerializationHelper.GetType(serverCommand.Details.Properties["Verb"].Value.ToString() + "Parameters");
            string xmlFragment = serverCommand.Details.Properties["SerializedParameters"].Value.ToString();

            StringReader stringReader = new StringReader(xmlFragment);
            XmlTextReader xmlReader = new XmlTextReader(stringReader);
            XmlSerializer xmlSer = new XmlSerializer(t);
            return xmlSer.Deserialize(xmlReader);
        }
    }

This server side class needs also the following class in the common project:

public static class CommonSerializationHelper
    {
        public static Type GetType(string typeName)
        {
            Type t = Type.GetType("LightSwitchApplication." + typeName);
            return t;
        }
    }

 

The base class, takes care of

  • the CanExecute handling;
  • the deserialization of the command parameters;
  • exception handling and updating the response accordingly.
  • keeping track (or not) of command history.

 

Conclusion

When commanding takes a prominent place in your LightSwitch project, it can make sense to use the above execution pipeline base infrastructure to make command handling less error-prone and more versatile.

You can download here the sample app: CommandTablePattern