Archive

Archive for May, 2010

Using C# Reflection for a simple Plugin System

May 14, 2010 1 comment

.NET Reflection is a very, very powerful tool. One thing I used it for is making a basic plugin system for my web server.

I needed some sort of way to know what assemblies to load, so I used a configuration file with a simple format to parse. For each module I wanted to load, I put a line that was the path to the DLL, preceded by the word “mod”

mod C:\modules\module.dll

I figured that me or someone else might write a plugin that used another external library, so I used “dep” to mark DLL’s that were needed for the modules.

dep C:\dependencies\dependency.dll

When the server starts up, it reads through this configuration file, takes all the lines that start with mod or dep and assigns puts their path in module and dependency ArrayList’s respectively. Once the config file is read, it goes through and loads the dependencies first.

 Assembly.LoadFile(DependencyPath);

Loading the modules is a little more complicated. For this I created a simple Module class to hold some information I would need about it, and be able to give me access to the Assembly object that loading the dll returns. In this case, when I load the module, I want to go into a class called ModuleMap that contains the url mapping info that I require for the plugin, and call its GetUrlMap method.

    public class Module
    {
        public string ModulePath;
		public string ModuleNamespace;
        public Assembly ModuleAssembly;
        public List<UrlMapItem> UrlMap;

        public Module(string modulepath)
        {
            ModulePath = modulepath;
        }

        public void Load()
        {
            if (!File.Exists(ModulePath))
            {
                throw new NoSuchModuleException("Error: No such module at '" + ModulePath + "'.");
            }
            ModuleAssembly = Assembly.LoadFile(ModulePath);
            int lastslash = ModulePath.LastIndexOf(@"\");
            string assemblynamespace = ModulePath.Substring(lastslash+1, ModulePath.LastIndexOf('.') - lastslash-1);
			ModuleNamespace = assemblynamespace;
            Type t = ModuleAssembly.GetType(assemblynamespace+".ModuleMap");
            if (t != null)
            {
                MethodInfo m = t.GetMethod("GetUrlMap");
                if (m != null)
                {
                    UrlMap = (List<UrlMapItem>)m.Invoke(null, (new object[]{}));
                }
                else
                {
                    throw new InvalidModuleMapException("Error: The ModuleMap class is incorrect!");
                }
            }
            else
            {
                throw new InvalidModuleMapException("Error: The ModuleMap class is missing!");
            }
        }
    }

When I use the Invoke() method, I passed it two arguments. In this case, since it is a static method, the first argument is null. The second argument is an object array that contains the arguments for the invoked method. The Invoke() method returns an instance of an object class, so I casted it into the object type I needed, which in this case was a List.

Now, that UrlMapClass, that I now have a list of, contains two pieces of information:

  • A url
  • A method with the full namespace/class path (ex. “testnamespace.testclass.methodname”)

Then I took a Hashtable and used the namespace.class.method path as the key, and the Module.ModuleAssembly as the value object. This way when I go to call it, I can enter the path that I know is being called, take the Assembly object, and do what I did before and call MethodInfo.Invoke().

Assembly assembly = (Assembly)ModuleList[methodnamespace];
Type t = assembly.GetType(method.Substring(0, method.LastIndexOf('.')));
MethodInfo m = t.GetMethod(method.Substring(method.LastIndexOf('.') + 1));
Page p = (Page)m.Invoke(null, (new object[] { rq }));

The method variable contained the whole method.class.methodname path and the methodnamespace variable contained just the namespace. To get the class for GetType() I used a substring of the whole namespace.class.methodname string that was from 0 to the last . which would give you just namespace.class.

This is a pretty simple example. I structured my plugin DLL’s in such a way that it gave me all the info I needed to call the corresponding methods in a very simple manner. There are obviously much more complex ways to do this.

Handling Multiple Connections: Asynchronous Network I/O with C#

May 1, 2010 1 comment

Here is a little tutorial for handling multiple simultaneous connections in C#.

The trick to doing asynchronous I/O with C# sockets is the AsyncCallback. You call the socket.Begin* methods, passing them an AsyncCallback object (which is a method) and a state object. The state object you pass is the socket itself. When the callback is called, it is passed an IAsyncResult. This contains the AsyncState, which is the state object you passed. You can cast it into a Socket and continue processing. Now we can get to the code:

The first thing we need is to include the proper references:

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

You may be wondering why we need System.Threading. This is because we need a ManualResetEvent. This is used to signal events between the methods.

We’ll now write a class called ServerRunner, which starts the serving by its method Run(). It has 3 other methods, AcceptCon(), SendData(), and ReceiveData(). All 3 methods take an IAsyncResult “iar”.

First we need a couple of class variables

        private Byte[] data = new Byte[2048];
        private int size = 2048;
        private Socket server;
        static ManualResetEvent allDone = new ManualResetEvent(false);

This gives us some stuff for the actual transmission of the data, and of course the ManualResetEvent that I explained earlier. Heres our Run method that starts everything:

        public void Run()
        {
            try
            {
                server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPEndPoint iep = new IPEndPoint(IPAddress.Any, 33333);
                server.Bind(iep);
                Console.WriteLine("Server initialized..");
                server.Listen(100);
                Console.WriteLine("Listening...");
                while (true)
                {
                    allDone.Reset();
                    server.BeginAccept(new AsyncCallback(AcceptCon), server);
                    allDone.WaitOne();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

This starts like any listening socket. Create an IPEndPoint and bind your server socket to it. Then call the listen method. Then you want to start an infinite loop calling the BeginAccept() method with the AsyncCallback and state object. Around it, you want your ManualResetEvent’s Reset() and WaitOne() methods. This makes it so it waits until the connection has actually been accepted and started to be dealt with before it can start to accept a new one. In the next method You’ll see the ManualResetEvent’s Set() method, which tells it that it is ok to continue to the next connection. Heres the AcceptCon() method we put as the AsyncCallback to the BeginAccpet()

        void AcceptCon(IAsyncResult iar)
        {
            allDone.Set();
            try
            {
                Socket oldserver = (Socket)iar.AsyncState;
                Socket client = oldserver.EndAccept(iar);
                Console.WriteLine(client.RemoteEndPoint.ToString() + " connected");
                byte[] message = Encoding.ASCII.GetBytes("Welcome");
                client.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(SendData), client);
            }
            catch (Exception)
            {
                Console.WriteLine("Connection closed..");
                return;
            }
        }

In this method, first we call the ManualResetEvent’s Set() method, which tells it that we have gotten what we need. Then we cast the iar.AsyncState (the state object we passed into the method, which was a Socket) back to what it originally was so we can use it. This code sends a simple “Welcome” message to the client that connects. However you can choose to do whatever you want. We then call the BeginSend method, again with an AsyncCallback (this time to the SendData() method) and a state object (this time client socket).

        void SendData(IAsyncResult iar)
        {
            try
            {
                Socket client = (Socket)iar.AsyncState;
                int sent = client.EndSend(iar);
                client.BeginReceive(data, 0, size, SocketFlags.None, new AsyncCallback(ReceiveData), client);
            }
            catch (Exception)
            {
                Console.WriteLine("Connection closed..");
                return;
            }
        }

This method finishes off the send, and then starts to listen for more data by calling the ReceiveData() method as an AsyncCallback, again passing the client socket as a state object.

        void ReceiveData(IAsyncResult iar)
        {
            try
            {
                Socket client = (Socket)iar.AsyncState;
                int recv = client.EndReceive(iar);
                if (recv == 0)
                {
                    client.Close();
                    server.BeginAccept(new AsyncCallback(AcceptCon), server);
                    return;
                }
                string receivedData = Encoding.ASCII.GetString(data, 0, recv);
                // process received data here
                // decide what to send back
                byte[] message2 = Encoding.ASCII.GetBytes("reply");
                client.BeginSend(message2, 0, message2.Length, SocketFlags.None, new AsyncCallback(SendData), client);
            }
            catch (Exception)
            {
                Console.WriteLine("Connection closed..");
                return;
            }
        }

This is where we do all the data handling. It takes in data, does what you need to do with the data, and sends back a response. In this method we check to see if the socket is done, in which case we close it, call BeginAccept again to continue listening, and return to end the method execution. This method doesn’t actually have any data handling in it, it simply sends the string “reply” as a response to every piece of data that comes in. But I left comments showing you where to put your methods to actually deal with the data and come up with a response. When we are done handling the data, we call the BeginSend, which sends off the data, and then goes back to receiving again. It continues until the connection is closed.

A small warning about this code: The only exception handling in here is to keep the server from crashing if the client disconnects unexpectedly. If you are planning to use this as any sort of production code, I suggest you put in much more detailed exception handling.

Well. There it is. It’s much simpler than I thought it was going to be, and it only requires those 3 methods really. Hope you can all put this to good use.

Follow

Get every new post delivered to your Inbox.