1

So i've been looking to impliment a VERY simple command interface for a services so that http cmds can be sent to it to control it.

The part im struggling with is the best way to implement the commands, which will be based on the route. I've seen a lot on the command pattern which makes sense, but there is one thing im trying to modify. In all cases there is a dictionary which has the commands, is there some way to get rid of the dictionary and, for example, look at all static methods in a class? Im sure this can be done with reflection but i have yet to see an example of it, and when ever i look for the command pattern and reflection most people say to stay away from it.

My main goal is to make sure that if someone adds a command they don't forget to add it to the dictionary, I know i want all static methods to respond to routes.

Is this a good idea or should i say screw it and just stick to the normal pattern?

I should add im using the HttpListener with a very basic web server similar to this Multi-threading with .Net HttpListener

and the best example i've seen of the command pattern for what im looking to do is this using the command and factory design patterns for executing queued jobs

Full Solution

//simple interface
interface ICommand
{
    bool Execute();
}

//example cmd
public class cmd_Restart:ICommand
{
    public bool Execute()
    {
        //put your code here
        //return true or false for success
        logger.writeLog("It was called!");
        return true;
    }
}

class commands
{
    private static Dictionary<string, Type> _commands;
    public commands()
    {
        loadCommands();
    }

    public ICommand GetCommand(string cmdName)
    {
        //should probably be more complex to make sure its found
        return (ICommand)Activator.CreateInstance(_commands[cmdName]);
    }

    private void loadCommands()
    {
        _commands = new Dictionary<string, Type>();
        var cmdType = typeof(ICommand);

        _commands = AppDomain.CurrentDomain.GetAssemblies()
            .First(a => a.GetName().Name == "DomoticzServiceManagerTest")
            .GetTypes()
            .Where(t => t.Name.StartsWith("cmd_"))
            .ToDictionary(c => c.Name.Substring(4).ToLower(),
                            c => c);
        }
}
Community
  • 1
  • 1
jrich523
  • 598
  • 1
  • 5
  • 19
  • you should start with Asp.net 101. I am pretty sure it will cover that part. – Steve Aug 02 '16 at 16:30
  • @steve well im not using ASP.NET or any web services related technologies. This is going to be a windows service that you can send to commands too via url rest(ish) calls – jrich523 Aug 02 '16 at 17:23

3 Answers3

2

Third time lucky!

Here is some code which will find all types implementing a particular interface, such as your ICommand interface.

Register each type in a Dictionary<string, Type> - type name vs type, say.

When a request comes in, get the type. From the dictionary and do something like this;

var command = (ICommand)Activator.CreateInstance(commandType);
command.Execute();

So now you've got a system that finds types without having to register them, and automatic dispatch.

It's a bit basic but it's a pattern that has worked for me in the past.

Community
  • 1
  • 1
Steve Cooper
  • 20,542
  • 15
  • 71
  • 88
1

Reflection is used both in ASP.NET MVC and WebAPI. So a method on a class

public class AccountController: Controller
{
    public ActionResult Login(string username, string password) 
    ...
}

Both the Controller classes and the action methods themselves are discovered by reflection and invoked by a runtime.

I guess you're talking about libraries like Nancy when you talk about dictionaries of commands?

I'd be tempted to go with an existing solution unless this is a learning experience. For example, if ASP.NET MVC already does what you want, is battle-tested, and is easy to get help for, then it might be a mistake to reinvent your own wheel.

Steve Cooper
  • 20,542
  • 15
  • 71
  • 88
1

You might want to look at MEF which will do the discovery part for you, and is built into the framework now.

What you then want is some kind of dispatcher. Something like a Nancy service with a route like:

Post["/:commandName"] = _ => {}

Then pick up the command name, and dispatch to the appropriate container.

The link in MEF contains a section with the word 'ImportMany' which shows how to dispatch commands based on a command name.

As a corollary; I've used TopShelf and Nancy successfully to host a Windows service that responds to HTTP.

Steve Cooper
  • 20,542
  • 15
  • 71
  • 88
  • hmm, i've used MEF before, but for more of a real plugin system, not for something this basic. im not sure i want to add the overhead for this, but i'll play around with it – jrich523 Aug 02 '16 at 20:51