Other Posts in AOP

  1. Creating an AOP Library in .Net - Part 1
  2. Creating an AOP Library in .Net - Part 2
  3. Creating an AOP Library in .Net - Part 3
  4. Creating an AOP Library in .Net - Part 4

Creating an AOP Library in .Net - Part 2

7/12/2010

I meant to post this last week but as always I have too much going on at once. In the first post about AOP, I talked about the various approaches that are commonly seen when implementing it and my choice for going forward. And for those that aren't interested in going back and reading the first post, I chose to do run time subclassing as a way to implement AOP. In this post I'll actually show the basic setup.

Starting off, the system is divided into two sections, the manager and the actual aspects. The manager is the central bit of code that sets up the subclass, gets the aspects wired up, etc. The aspects are the bits of code that we want to weave into our existing code base with each one handling one task. For instance tracing/logging would be one aspect, caching would be another, etc. So let's look at our basic manager first:

   1: namespace Aspectus
   2:  
   3: {
   4:  
   5:     public class Manager:Singleton<Manager>
   6:  
   7:     {
   8:  
   9:         protected Manager()
  10:  
  11:             : base()
  12:  
  13:         {
  14:  
  15:             Configuration = Gestalt.Manager.Instance.GetConfigFile<Configuration>("AspectusConfiguration");
  16:  
  17:             Classes = new Dictionary<Type, Type>();
  18:  
  19:             AssemblyName Name = new AssemblyName(Configuration.AssemblyName);
  20:  
  21:             AppDomain Domain = Thread.GetDomain();
  22:  
  23:             Builder = Domain.DefineDynamicAssembly(Name, AssemblyBuilderAccess.RunAndSave, Configuration.AssemblyDirectory);
  24:  
  25:             Module = Builder.DefineDynamicModule(Configuration.AssemblyName, Configuration.AssemblyName + ".dll", true);
  26:  
  27:         }
  28:  
  29:  
  30:  
  31:         public void Save()
  32:  
  33:         {
  34:  
  35:             Builder.Save(Configuration.AssemblyName + ".dll");
  36:  
  37:         }
  38:  
  39:  
  40:  
  41:         public void Setup(Type Type)
  42:  
  43:         {
  44:  
  45:             List<Type> Interfaces = new List<Type>();
  46:  
  47:             TypeBuilder TypeBuilder = Module.DefineType(Configuration.AssemblyName + "." + Type.Name + "Derived", TypeAttributes.Public, Type, Interfaces.ToArray());
  48:  
  49:             MethodAttributes GetSetAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual;
  50:  
  51:  
  52:  
  53:             foreach (MethodInfo Method in Type.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance))
  54:  
  55:             {
  56:  
  57:                 if (Method.IsVirtual)
  58:  
  59:                 {
  60:  
  61:                     CreateMethod(Type, Method, TypeBuilder);
  62:  
  63:                 }
  64:  
  65:             }
  66:  
  67:  
  68:  
  69:             Classes.Add(Type, TypeBuilder.CreateType());
  70:  
  71:         }
  72:  
  73:  
  74:  
  75:         public T Create<T>()
  76:  
  77:         {
  78:  
  79:             T ReturnObject = (T)Classes[typeof(T)].Assembly.CreateInstance(Classes[typeof(T)].FullName);
  80:  
  81:             return ReturnObject;
  82:  
  83:         }
  84:  
  85:  
  86:  
  87:         private void CreateMethod(Type Type, MethodInfo Method, TypeBuilder TypeBuilder)
  88:  
  89:         {
  90:  
  91:  
  92:  
  93:         }
  94:  
  95:  
  96:  
  97:         protected AssemblyBuilder Builder { get; set; }
  98:  
  99:         protected ModuleBuilder Module { get; set; }
 100:  
 101:         protected Dictionary<Type, Type> Classes { get; set; }
 102:  
 103:         protected Configuration Configuration { get; set; }
 104:  
 105:     }
 106:  
 107: }

First off, the manager class uses a base class of Singleton. It's nothing more than a generic singleton class that has one property Instance. This simply allows me to access this class anywhere without pointer passing. In the constructor, we first grab the configuration file from Gestalt.Net and saves it for later. The configuration class simply holds the assembly name desired and the directory it should be saved to when the Save function is called. Past that we set up the Classes object, create an AssemblyName object, get the current AppDomain, etc. The last two lines create a dynamic assembly and a dynamic module (we're going to be doing some IL generation so this is required). The AssemblyBuilder is the actual assembly that we will be generating. In this case we name it, set it so that we can run it as well as save it to disk, and set the directory it can be saved in. The ModuleBuilder needs the same name as the assembly, the reason for this is that the first module created for an assembly acts as the manifest for that assembly. As such, since we're only creating one module, we need the assembly and module to match up.

The second function is Save, which simply saves the assembly to disk. After that is a function called Setup. Setup is where we are actually weaving in our aspects (well in the future we will weave them in there). In the function now we define a type that is public and uses the type passed in as the base class. We then go through and loop through each method within the base class. You'll notice that we set a bunch of bindings (Nonpublic, public, etc.) instead of simply calling GetMethods. The reason we aren't calling the default is that by default all it will return are public methods. We however want to be able to override protected and public functions, whether they are static or not. However this returns everything and not just virtual methods. Since we can only override virtual methods, we need to check for that. After this we call CreateMethod (which would override the method but is empty at the moment). Once we are done we create the newly formed sub type and save it within our class dictionary.

The last function in the class is Create. This is a generic function which creates a new instance of a class based on the type sent into it. With this class we can do the following at present:

   1: Aspectus.Manager.Instance.Setup(typeof(MyType));
   2: MyType MyObject=Aspectus.Manager.Instance.Create<MyType>();

This would set up the type and create an instance of MyTypeDerived, which is simply a subclass of MyType. Nothing would need to change in the programming (other than calling Create instead of new MyType()). Anyway, at this point that's all there is to the basic setup of the manager. In the next post I'll show setting up the actual aspects in a couple different ways. Anyway, happy coding.



Comments