Thursday, June 6, 2013

Introducing: InteractionLib

What is InteractionLib?

InteractionLib, as with most of my side-projects, was formed out of necessity. My team at work is responsible for pumping out small web-based corporate tooling for internal functions. In my line of work it is necessary to constantly find ways to optimize process and increase productivity.  

Today web-based applications are common and tooling for productivity is plentiful. So the question is: Why am I not using an all-inclusive framework package? Solid names like Telerik may immediately come to mind - and don't get me wrong, those guys over there are pretty damn smart - but their products, like so many others, are their product with their look and feel. So the answer to the question is: I work for Blizzard.

And just as with Blizzard external products, Blizzard internal products require a certain level of awesome. I am not in any way saying that these aforementioned products don't emanate all sorts of awesome, but they are a very specific awesome that commonly require more time and work to customize to a Blizzard designer's look and feel.

This is where the framework library InteractionLib comes in. My necessity at work is that I need a way to increase my ability to produce a look and feel for a new tool quickly that will have little or no re-usability between projects. The only way to do this is to create a framework that attempts to optimize implementation without actually implementing anything.

InteractionLib attempts to accomplish this by not only streamlining the wire up of client-side interactions, but also making back-and-forth server-client communications literally take seconds to implement. With InteractionLib I am able to wire up complex single-page-applications (SPA) with almost no effort and in even less time.

By creating a framework around current best patterns & practices InteractionLib provides a clean and maintainable method for me to eliminate time-consuming configurations and focus on meaningful, presentable code.

Let's take a look at one common configuration of apps-from-scratch out in the wild:


What this typically translates to is a page which has its own "configuration" .js file. That file will find various IDs and classes on the page and wire these up the to appropriate plugins and create the appropriate interactions for the page.

Individually these little interaction wire-ups are small and inconsequential. But a single page will have a number of these interactions, each adding up to a significant amount of time and repetitive code. I've actually worked with developer's in the past who would literally write the same block of javascript over and over again without a second thought to efficiency and maintainability.



What InteractionLib does for me is completely cuts out the middle man. In many cases InteractionLib can handle the interaction all on its own leaving even less code to be written.

Additionally InteractionLib allows my pages to pick and choose what they need to be wired up to. More importantly is it also allows me to do my wire ups directly in my markup making my page more descriptive and ultimately more maintainable.



To demonstrate this take a look at the wire-up below for a custom plugin:
  1. <div class="my-plugin plugin-option-1 plugin-option-2"></div>
This is then identified by some wire-up code...

  1.     $('.my-plugin').each(function () {
  2.         var element = $(this);
  3.         var option1 = element.hasClass('plugin-option-1');
  4.         var option2 = element.hasClass('plugin-option-2');
  5.         element.myPlugin({ option1: option1, option2: option2 });
  6.     });
Alone this is a very small amount of code to be worried about. However, 10 plugins and 30 pages later, I now have a maintenance nightmare. When I come back to this application a year later to make some updates I don't know where to find this code. When I do figure out what file these configurations are in, I then have to search through hundreds of lines of wire-up code to find the wire-up I want to alter.

Below is the InteractionLib way to wire this plugin up:

  1. <div data-interaction="myPlugin"
  2.      data-configuration-option1="true"
  3.      data-configuration-option2="true"></div>

  • I no longer need to write any wire-up code, nor do I have to need an extra .js file to store it in
  • I can come back to this project years later and immediately recognize exactly what is wired up here and how
  • I no longer have to worry about a designer attaching styles to a class on my element that was meant for functionality
  • My wire-ups here also respond to ajaxed content that comes in after the page has finished loading (SPAs).

Now, I also said that InteractionLib handles server communications. It does this by wrapping the jQuery AJAX library and exposing it through a number of easy-to-use data attributes. Before I get into these attributes, though, I want to discuss the basic workflow that InteractionLib is trying to encapsulate.

The process of a user interaction can be broken down into these four simple parts. The user does something, the page sends a query to the server, the server returns a response, and the page inserts the response.

Effectively what this breaks down to in the web is a "form" that uses AJAX instead of an actual form post, and then has a designated space or way to display the resulting HTML or JSON returned from the server.

A very common example of this would be a search text input that sends the search results back to the server. The server then sends back a block of HTML rows (<tr>) containing the search results. The resulting HTML then replaces the content that was previously in the body of the table displaying the results. Each time the user changes the search text, the results are updated without making a complete page-update and only loading the minimal amount of HTML to display results.

The old way of doing this required an ID or some identifier that could easily be mistaken by a designer as something that can be renamed, removed, or used for styling. That ID would be searched for by some javascript hidden in a .js file somewhere that is difficult to find year(s) later. Once found, a keydown event would be attached to the text input that would wait until the enter key was pressed. When an enter key has been detected, the text from the input is sent to a hard-coded address on the server which will likely change one day leaving this functionality magically broken. After a response is returned from the server, the javascript will find the place on the page where the results must go, clear out any previous results, and place the new results there.

The little chunk of code for doing all this would be around 10 - 40 lines of jQuery AJAX vomit, repeated half a dozen times per page for every user interaction like this. Of course the developer comments and optimizes the code the best they can, but ultimately time will be spent the next time this application is updated reading through the sewer that is this application's client-side code.

This is where InteractionLib will make the biggest impact.

  1. <!-- using just ajaxform-action and ajaxform-target -->
  2. <!-- this entire interaction is taken care of -->
  3. <!-- using no additional javascript -->
  4. <form data-ajaxform-action="Some/Server/Action"
  5.       data-ajaxform-target="#server-response">
  6.     <label>
  7.         Search Criteria
  8.         <input type="text" name="criteria"/>
  9.     </label>
  10.     <button type="submit">Search</button>
  11. </form>
  12. <table>
  13.     <tbody id="server-response">
  14.         <!-- The resulting rows from the server -->
  15.         <!-- will be placed here (ajaxform-target) -->
  16.     </tbody>
  17. </table>
By taking this process and streamlining it into a few data-attributes I can hook up this entire interaction without writing any of the previously required boiler plate code. InteractionLib also provides me with custom eventing and other hooks allowing me to tap into the process at any point and customize the experience. This means the only code I am writing is meaningful code. It also means that the next time I return to this page I don't need to do any searching to know exactly what is wired up to this page. This reduces both my initial development time and time spent maintaining the application.

If you would like to know more about InteractionLib you can find the project on GitHub.com, Nuget.org, and the documentation at markonthenet.com/InteractionLib.

You can also contact me on markonthenet.com/Me if you have any questions, comments, or requests for InteractionLib.

Thursday, April 19, 2012

Dynamic Types and Assemblies in .NET

Here is a tinker I did with the .net reflection library to do some dynamic type generation. There are testing mock libraries out there that do this and are way more robust, but being what it is I thought I would post it in case anyone else became curious about this. Prepare for a huge code dump below!


using System;
using
 System.Collections.Generic;
using
 System.Linq;
using
 System.Reflection;
using
 System.Reflection.Emit;
namespace
 Dynamic
{
    
/// <summary>
    
/// Represents a virtual assembly in memory
    
/// </summary>
    
public class Namespace : IDisposable
    {
        
private readonly AssemblyName _assemblyName;
        
private readonly AssemblyBuilder _assemblyBuilder;
        
private readonly ModuleBuilder _moduleBuilder;

        
private readonly List<Type> _classes = new List<Type>();
        
/// <summary>
        
/// A collection of classes belonging to this dynamic namespace
        
/// </summary>
        
public Type[] Classes { get { return _classes.ToArray(); } }

        
private readonly List<Type> _interfaces = new List<Type>();
        
/// <summary>
        
/// A collection of interfaces belonging to this dynamic namespace
        
/// </summary>
        
public Type[] Interfaces { get { return _interfaces.ToArray(); } }

        
private readonly List<Type> _enums = new List<Type>();
        
/// <summary>
        
/// A collection of enums belonging to this dynamic namespace
        
/// </summary>
        
public Type[] Enums { get { return _enums.ToArray(); } }

        
/// <summary>
        
/// Creates a new dynamic namespace for containing simple dynamic types
        
/// </summary>
        
public Namespace()
        {
            _assemblyName = 
new AssemblyName(Guid.NewGuid().ToString());
            
// Assembly builder MUST be set to run and collect to be disposable. The dynamic assembly will participate in normal garbage collection when all references to it and its types are released.
            
// REF: http://msdn.microsoft.com/en-us/library/dd554932.aspx
            _assemblyBuilder = 
AppDomain.CurrentDomain.DefineDynamicAssembly(_assemblyName, AssemblyBuilderAccess.RunAndCollect);
            _moduleBuilder = _assemblyBuilder.DefineDynamicModule(_assemblyName.Name, _assemblyName.Name + 
".dll");
        }

        
/// <summary>
        
/// Creates a dynamic type that lives in this dynamic namespace
        
/// </summary>
        
/// <param name="name">The name of the dynamic type</param>
        
/// <param name="properties">A collection of auto-properties the dynamic type will have</param>
        
/// <param name="fields">A collection of read/write fields the dynamic type will have</param>
        
/// <param name="baseType">Optional base type for this dynamic type to inherit from</param>
        
/// <param name="ifaces">Optional interfaces this dynamic type implements</param>
        
/// <param name="attrs">Optional interfaces this dynamic type implements</param>
        
/// <returns>The created dynamic type</returns>
        
public Type CreateClass(string name, Property[] properties, Property[] fields, Type baseType = null, Type[] ifaces = null, Attribute[] attrs = null)
        {
            baseType = baseType ?? 
typeof(object);

            
// Define Type
            
var builder = _moduleBuilder.DefineType(name, TypeAttributes.Public, baseType, ifaces);

            
// ImplementInterfaces
            (ifaces ?? 
new Type[0]).ToList().ForEach(builder.AddInterfaceImplementation);

            
// Define Attributes
            (attrs ?? 
new Attribute[0]).ToList().ForEach(a => builder.SetCustomAttribute(GetAttributeBuilder(a)));

            
// Define Properties
            (properties ?? 
new Property[0]).ToList().ForEach(p => GetAutoPropertyBuilder(builder, p, ifaces));

            
// Define Fields
            (fields ?? 
new Property[0]).ToList().ForEach(f => builder.DefineField(f.Name, f.Type, FieldAttributes.Public));

            
// Forwarding all constructors
            
var baseCtors = baseType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            
foreach (var baseCtor in baseCtors)
            {
                
// Getting parameter information
                
var parms = baseCtor.GetParameters();
                
var parmTypes = parms.Select(p => p.ParameterType).ToArray();
                
var reqModifiers = parms.Select(p => p.GetRequiredCustomModifiers()).ToArray();
                
var optModifiers = parms.Select(p => p.GetOptionalCustomModifiers()).ToArray();
                
if (parms.Length > 0 && parms.Last().IsDefined(typeof(ParamArrayAttribute), false)) { continue; }

                
var ctor = builder.DefineConstructor(MethodAttributes.Public, baseCtor.CallingConvention, parmTypes, reqModifiers, optModifiers);

                
// Adding parameters
                
for (var i = 0; i < parms.Length; i++)
                {
                    
var parm = ctor.DefineParameter(i + 1, parms[i].Attributes, parms[i].Name);
                    
if (((int)parms[i].Attributes & (int)ParameterAttributes.HasDefault) != 0)
                    {
                        parm.SetConstant(parms[i].RawDefaultValue);
                    }
                    parms[i].DynamicAttributes()
                        .ToList()
                        .ForEach(a => parm.SetCustomAttribute(GetAttributeBuilder(a)));
                }

                
// Setting attributes
                baseCtor.DynamicAttributes()
                    .ToList()
                    .ForEach(a => ctor.SetCustomAttribute(GetAttributeBuilder(a)));

                
// Forwarding parameters to baseCtor
                
var il = ctor.GetILGenerator();
                il.Emit(
OpCodes.Nop);

                
// Loading args
                il.Emit(
OpCodes.Ldarg_0); // 'this'
                
for (var i = 1; i <= parms.Length; i++)
                    il.Emit(
OpCodes.Ldarg, i); // param i
                
// Calling baseCtor with loaded args
                il.Emit(
OpCodes.Call, baseCtor);
                il.Emit(
OpCodes.Ret);
            }

            _classes.Add(builder.CreateType()); 
// Generate Type and return
            
return _classes.Last();
        }

        
/// <summary>
        
/// Creates an dynamic enum type that lives in this dynamic namespace
        
/// </summary>
        
/// <typeparam name="TBase">The underlying value type for this enumeration</typeparam>
        
/// <param name="name">The name of this dynamic enum</param>
        
/// <param name="values">A collection of names/values this dynamic enum will have</param>
        
/// <returns>The created dynamic enum</returns>
        
public Type CreateEnum<TBase>(string name, IDictionary<string, TBase> values)
        {
            
var builder = _moduleBuilder.DefineEnum(name, TypeAttributes.Public, typeof(TBase));

            
// Create literals
            
foreach (var value in values)
            {
                builder.DefineLiteral(value.Key, value.Value);
            }

            _enums.Add(builder.CreateType());
            
return _enums.Last();
        }

        
/// <summary>
        
/// Creates an dynamic interface type that lives in this dynamic namespace
        
/// </summary>
        
/// <param name="name">The name of this dynamic interface</param>
        
/// <param name="properties">The property signatures for this dynamic interface</param>
        
/// <param name="methods">The method signatures for this dynamic interface</param>
        
/// <param name="ifaces">Optional interfaces this dynamic interface implements</param>
        
/// <returns>The dynamic interface</returns>
        
public Type CreateInterface(string name, Property[] properties, Method[] methods, Type[] ifaces = null, Attribute[] attrs = null)
        {
            
// Define Type
            
var builder = _moduleBuilder.DefineType(name, TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract, null, ifaces);

            
// Define Attributes
            (attrs ?? 
new Attribute[0]).ToList().ForEach(a => builder.SetCustomAttribute(GetAttributeBuilder(a)));

            
// Define Properties
            
var propertyAttrs = MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract | MethodAttributes.VtableLayoutMask | MethodAttributes.SpecialName;
            
foreach (var property in properties ?? new Property[0])
            {
                
var pbuild = GetPropertyBuilder(builder, property);
                pbuild.SetGetMethod(builder.DefineMethod(
"get_" + property.Name, propertyAttrs, property.Type, Type.EmptyTypes));
                pbuild.SetSetMethod(builder.DefineMethod(
"set_" + property.Name, propertyAttrs, typeof(void), new[] { property.Type }));
            }
            (properties ?? 
new Property[0]).ToList().ForEach(p => GetPropertyBuilder(builder, p));

            
// Define Methods
            
foreach (var method in methods ?? new Method[0])
            {
                
var methBuilder = builder.DefineMethod(
                    method.MethodName, 
MethodAttributes.Public | MethodAttributes.Abstract | MethodAttributes.Virtual,
                    method.ReturnType, method.Parameters.Select(p => p.Type).ToArray());

                (method.Attributes ?? 
new Attribute[0]).ToList().ForEach(a => methBuilder.SetCustomAttribute(GetAttributeBuilder(a)));

                
for (var i = 0; i < method.Parameters.Length; i++)
                {
                    
var parm = method.Parameters[i];
                    
var parmBuilder = methBuilder.DefineParameter(i + 1, ParameterAttributes.None, parm.Name);
                    (parm.Attributes ?? 
new Attribute[0]).ToList().ForEach(a => parmBuilder.SetCustomAttribute(GetAttributeBuilder(a)));
                }
            }

            _interfaces.Add(builder.CreateType()); 
// Generate Type and return
            
return _interfaces.Last();
        }

        
private CustomAttributeBuilder GetAttributeBuilder(Attribute attribute)
        {
            
if (attribute.Properties.Count > 0 && attribute.Fields.Count > 0)
                
return new CustomAttributeBuilder(attribute.Constructor, attribute.Parameters,
                    attribute.Properties.Keys.ToArray(), attribute.Properties.Values.ToArray(),
                    attribute.Fields.Keys.ToArray(), attribute.Fields.Values.ToArray());
            
if (attribute.Properties.Count > 0)
                
return new CustomAttributeBuilder(attribute.Constructor, attribute.Parameters,
                    attribute.Properties.Keys.ToArray(), attribute.Properties.Values.ToArray());
            
if (attribute.Fields.Count > 0)
                
return new CustomAttributeBuilder(attribute.Constructor, attribute.Parameters,
                    attribute.Fields.Keys.ToArray(), attribute.Fields.Values.ToArray());
            
return new CustomAttributeBuilder(attribute.Constructor, attribute.Parameters);
        }

        
private PropertyBuilder GetAutoPropertyBuilder(TypeBuilder builder, Property property, Type[] ifaces)
        {
            
var field = builder.DefineField("_" + property.Name.ToLower() + "_field", property.Type, FieldAttributes.Private);
            
var pbuilder = GetWiredPropertyBuilder(builder, property, ifaces,
                get =>
                {
                    get.Emit(
OpCodes.Ldarg_0);
                    get.Emit(
OpCodes.Ldfld, field);
                    get.Emit(
OpCodes.Ret);
                },
                set =>
                {
                    set.Emit(
OpCodes.Ldarg_0);
                    set.Emit(
OpCodes.Ldarg_1);
                    set.Emit(
OpCodes.Stfld, field);
                    set.Emit(
OpCodes.Ret);
                });
            
return pbuilder;
        }

        
private PropertyBuilder GetWiredPropertyBuilder(TypeBuilder builder, Property property, Type[] ifaces, Action<ILGenerator> getter, Action<ILGenerator> setter)
        {
            
var prop = GetPropertyBuilder(builder, property);
            
var iprops = (ifaces ?? new Type[0]).Select(i => i.GetProperty(property.Name)).Where(p => p != null).ToList();

            
if (getter != null)
            {
                
var igets = iprops.Select(p => p.GetGetMethod()).Where(g => g != null).ToList();
                
var attr = igets.Count == 0
                    ? 
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig
                    : 
MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
                
var get = builder.DefineMethod("get_" + property.Name, attr, property.Type, Type.EmptyTypes);
                getter(get.GetILGenerator());
                prop.SetGetMethod(get);
                igets.ForEach(g => builder.DefineMethodOverride(get, g));
            }

            
if (setter != null)
            {
                
var isets = iprops.Select(p => p.GetSetMethod()).Where(s => s != null).ToList();
                
var attr = isets.Count == 0
                    ? 
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig
                    : 
MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
                
var set = builder.DefineMethod("set_" + property.Name, attr, typeof(void), new[] { property.Type });
                setter(set.GetILGenerator());
                prop.SetSetMethod(set);
                isets.ForEach(s => builder.DefineMethodOverride(set, s));
            }

            
return prop;
        }

        
private PropertyBuilder GetPropertyBuilder(TypeBuilder builder, Property property)
        {
            
var prop = builder.DefineProperty(property.Name, PropertyAttributes.None, property.Type, null);

            
// Defining Attributes
            (property.Attributes ?? 
new Attribute[0]).ToList().ForEach(a => prop.SetCustomAttribute(GetAttributeBuilder(a)));

            
return prop;
        }

        
/// <summary>
        
/// Releases internal references to the dynamic assembly <br />
        
/// WARNING: The memory consumed by a dynamic assembly and its types will not be released until all references to its types have been released from your code.
        
/// </summary>
        
public void Dispose()
        {
            _classes.Clear();
            _enums.Clear();
            _interfaces.Clear();
        }

        
public class Method
        {
            
public string MethodName { get; private set; }
            
public Type ReturnType { get; private set; }
            
public Parameter[] Parameters { get; private set; }
            
public Attribute[] Attributes { get; private set; }

            
public Method(string name, Type ret, Parameter[] parms, Attribute[] attr = null)
            {
                MethodName = name;
                ReturnType = ret;
                Parameters = parms;
                Attributes = attr;
            }
        }

        
public class Parameter
        {
            
public string Name { get; private set; }
            
public Type Type { get; private set; }
            
public Attribute[] Attributes { get; private set; }

            
public Parameter(string name, Type type, Attribute[] attr = null)
            {
                Name = name;
                Type = type;
                Attributes = attr;
            }
        }

        
public class Property
        {
            
public string Name { get; private set; }
            
public Type Type { get; private set; }
            
public Attribute[] Attributes { get; private set; }

            
public Property(string name, Type type, Attribute[] attr = null)
            {
                Name = name;
                Type = type;
                Attributes = attr;
            }
        }

        
public class Attribute
        {
            
public Type Type { get; private set; }
            
public ConstructorInfo Constructor { get; private set; }
            
public object[] Parameters { get; private set; }
            
public Dictionary<PropertyInfo, object> Properties { get; private set; }
            
public Dictionary<FieldInfo, object> Fields { get; private set; }

            
public Attribute(Type type, ConstructorInfo ctor, object[] parms, IDictionary<PropertyInfo, object> props, IDictionary<FieldInfo, object> fields)
            {
                Type = type;
                Constructor = ctor;
                Parameters = parms;
                Properties = props.ToDictionary(d => d.Key, d => d.Value);
                Fields = fields.ToDictionary(d => d.Key, d => d.Value);
            }
        }
    }

    
public static class DynamicExtensions
    {
        
public static Namespace.Method[] DynamicMethods(this Type type)
        {
            
return type.GetMethods()
                .Select(m => 
new Namespace.Method(m.Name, m.ReturnType, m.GetParameters()
                    .Select(p => 
new Namespace.Parameter(p.Name, p.ParameterType))
                    .ToArray(), m.DynamicAttributes()))
                .ToArray();
        }

        
public static Namespace.Property[] DynamicProperties(this Type type)
        {
            
return type.GetProperties()
                .Select(p => 
new Namespace.Property(p.Name, p.PropertyType))
                .ToArray();
        }

        
public static Namespace.Attribute[] DynamicAttributes(this MemberInfo member)
        {
            
return member.GetCustomAttributesData().Select(ConvertAttribute).ToArray();
        }

        
public static Namespace.Attribute[] DynamicAttributes(this ParameterInfo param)
        {
            
return param.GetCustomAttributesData().Select(ConvertAttribute).ToArray();
        }

        
private static Namespace.Attribute ConvertAttribute(CustomAttributeData data)
        {
            
return new Namespace.Attribute(
                data.Constructor.DeclaringType, data.Constructor, data.ConstructorArguments.Select(p => (
object)p.Value).ToArray(),
                (data.NamedArguments ?? 
new CustomAttributeNamedArgument[0]).Where(p => p.MemberInfo is PropertyInfo).ToDictionary(p => (PropertyInfo)p.MemberInfo, p => p.TypedValue.Value),
                (data.NamedArguments ?? 
new CustomAttributeNamedArgument[0]).Where(p => !(p.MemberInfo is FieldInfo)).ToDictionary(p => (FieldInfo)p.MemberInfo, p => p.TypedValue.Value));
        }
    }
}
Basically you can just copy/paste this into a single .cs file in your project to try it out and see how it works. This is all System.Reflection.Emit with a small amount of IL in there. Most of this is just knowing how types are structured after being compiled and then just using the Emit builders to put it all together. What I've done here is packaged everything in a "hopefully" easy to understand API that allows you to create very simple class, interface, and enum types with auto-properties and what-not. If this helped you with some project somewhere it would be cool to hear about it. (www.markonthenet.com)