Saturday, June 21, 2014

Interface Proxy with Emit

You can find this project here: https://github.com/DataDink/Proxy

Before you read any further please see these much more tested and performant proxy solutions:
Be warned: What you are about to see is untested and most likely unperformant, unstable, unfriendly, and unsupported. Don't say I didn't warn you...

However, if you are like me and you just want a tiny solution to call your own, or even just wanting to learn something about dynamic proxy generation then please proceed!

Today I decided to try my hand at making a very simple, single-class proxy. The purpose for something like this would be to be able to implement an interface at run time to either wrap some kind of communication / IO layer or proxy an existing instance of that interface allowing me to intercept method and property interactions.

For example: Let's say I have an application that has a bunch of services that it interacts with. After the application is already written I decide I need to start logging information about each call to my services. I really don't want to go into every method on every service and add calls to a logger. Nor do I want to change the way my application interacts with my services. I'm way too lazy for that!

One annoying way to solve this problem would be to write a whole new class for each service interface that keeps an instance of the actual service and forwards calls to it after logging. Not the most desirable solution since I now have to write even more code than I was when I was just adding logging to the actual service methods. On top of this I would now have 2 classes to maintain if the service's interface is ever added to or changed.

What I really want to do is automate or generate this wrapper dynamically, yet still be able to function in a strongly typed environment. As I've stated before there are a number of existing solutions that will allow me to do this, but for this post I wanted to dive a little deeper and see how this stuff works for myself.

What it does:

Below I have an abstract Proxy<T> base class. This doesn't need to be abstract, but isn't terribly useful by itself as I have written it. The point of this implementation would be to extend this to a concrete class that is more useful for a specific use-case (of which I have several).

  1.     public abstract class Proxy<T> where T : class
  2.     {
  3.         #region Static Cache (NOTE: This is per T)
  4.         /// <summary>
  5.         /// The dynamic proxy type 
  6.         /// </summary>
  7.         protected static readonly Type InstanceType;
  8.         /// <summary>
  9.         /// The type of T
  10.         /// </summary>
  11.         protected static readonly Type Interface;
  12.         private static readonly Dictionary<intMethodInfo> MethodIndex;
  13.         /// <summary>
  14.         /// Looks up the MethodInfo for type T by index
  15.         /// </summary>
  16.         public static MethodInfo Lookup(int index) { return MethodIndex[index]; }
  17.         private static AssemblyBuilder Assembly;
  18.         /// <summary>
  19.         /// Saves the underlying generated assembly to disk
  20.         /// </summary>
  21.         public static void Save() { Assembly.Save(Assembly.GetName().Name + ".dll"); }
  22.         static Proxy()
  23.         {
  24.             Interface = typeof(T);
  25.             if (!Interface.IsInterface) throw new InvalidOperationException(string.Format("{0} is not an interface", Interface.Name));
  26.             MethodIndex = Interface.GetMethods().Select((m, i) => new {m, i}).ToDictionary(i => i.i, m => m.m);
  27.             InstanceType = Generate();
  28.         }
  29.         #endregion
  30.         /// <summary>
  31.         /// The underlying instance being proxied or null
  32.         /// </summary>
  33.         protected T Target { getprivate set; }
  34.         /// <summary>
  35.         /// The proxy instance
  36.         /// </summary>
  37.         protected T Instance { getprivate set; }
  38.         protected Proxy() { Instance = (T)Activator.CreateInstance(InstanceType, this); }
  39.         protected Proxy(T target) : this() { Target = target; } 
  40.         /// <summary>
  41.         /// Invokes the call handlers for this proxy
  42.         /// </summary>
  43.         public object Trigger(MethodInfo method, object[] parameters)
  44.         {
  45.             BeforeCall(method, parameters);
  46.             var result = OnCall(method, parameters);
  47.             AfterCall(method, parameters, result);
  48.             return result;
  49.         }
  50.         /// <summary>
  51.         /// Called prior to OnCall
  52.         /// </summary>
  53.         protected virtual void BeforeCall(MethodInfo method, object[] parameters) {}
  54.         /// <summary>
  55.         /// Called after OnCall
  56.         /// </summary>
  57.         protected virtual void AfterCall(MethodInfo method, object[] parameters, object result) {}
  58.         /// <summary>
  59.         /// When overridden should handle invoking the MethodInfo on Target if any
  60.         /// </summary>
  61.         protected virtual object OnCall(MethodInfo method, object[] parameters)
  62.         {
  63.             if (Target == nullreturn method.ReturnType.IsValueType ? Activator.CreateInstance(method.ReturnType) : null;
  64.             return method.Invoke(Target, parameters);
  65.         }
  66.         #region Emit Generation (
  67.         private static Type Generate()
  68.         {
  69.             var rootname = new AssemblyName(Interface.Name + "Proxy_" + Guid.NewGuid());
  70.             var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(rootname, AssemblyBuilderAccess.RunAndSave);
  71.             var module = assembly.DefineDynamicModule(rootname.Name, rootname.Name + ".dll");
  72.             var builder = module.DefineType(rootname.Name + ".Proxy"TypeAttributes.Class, typeof(object), new[] { typeof(T) });
  73.             var proxy = builder.DefineField("_proxy"typeof (Proxy<T>), FieldAttributes.Private);
  74.             
  75.             ConfigureConstructor(builder, proxy);
  76.             ConfigureInterface<T>(builder, proxy);
  77.             Assembly = assembly;
  78.             return builder.CreateType();
  79.         }
  80.         private static void ConfigureConstructor(TypeBuilder builder, FieldInfo proxy)
  81.         {
  82.             var ctor = builder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new[] { typeof(Proxy<T>) });
  83.             var ctorBase = typeof (object).GetConstructor(new Type[0]);
  84.             var encoder = ctor.GetILGenerator();
  85.             encoder.Emit(OpCodes.Ldarg_0);
  86.             encoder.Emit(OpCodes.Call, ctorBase);
  87.             encoder.Emit(OpCodes.Ldarg_0);
  88.             encoder.Emit(OpCodes.Ldarg_1);
  89.             encoder.Emit(OpCodes.Stfld, proxy);
  90.             encoder.Emit(OpCodes.Ret);
  91.         }
  92.         private static void ConfigureInterface<TIFace>(TypeBuilder builder, FieldInfo proxy = null)
  93.         {
  94.             var members = typeof (TIFace).GetMembers();
  95.             var methods = members.OfType<MethodInfo>().Where(m => !m.IsSpecialName).ToList();
  96.             var properties = members.OfType<PropertyInfo>().ToList();
  97.             methods.ForEach(m => ConfigureMethod(builder, proxy, m));
  98.             properties.ForEach(p => ConfigureProperty(builder, proxy, p));
  99.         }
  100.         private static void ConfigureProperty(TypeBuilder builder, FieldInfo proxy, PropertyInfo info)
  101.         {
  102.             var property = builder.DefineProperty(
  103.                 info.Name,
  104.                 info.Attributes,
  105.                 CallingConventions.HasThis,
  106.                 info.PropertyType,
  107.                 new Type[0]);
  108.             if (info.CanRead) property.SetGetMethod(ConfigureMethod(builder, proxy, info.GetGetMethod()));
  109.             if (info.CanWrite) property.SetSetMethod(ConfigureMethod(builder, proxy, info.GetSetMethod()));
  110.         }
  111.         private static MethodBuilder ConfigureMethod(TypeBuilder builder, FieldInfo proxy, MethodInfo info)
  112.         {
  113.             var index = MethodIndex.First(m => m.Value == info).Key;
  114.             var method = builder.DefineMethod(
  115.                 info.Name,
  116.                 (MethodAttributes.Public | MethodAttributes.Virtual | info.Attributes | MethodAttributes.Abstract) ^ MethodAttributes.Abstract,
  117.                 CallingConventions.HasThis,
  118.                 info.ReturnType,
  119.                 info.GetParameters().Select(p => p.ParameterType).ToArray());
  120.             var encoder = method.GetILGenerator();
  121.             ConfigureCall(encoder, proxy, info, index);
  122.             return method;
  123.         }
  124.         private static void ConfigureCall(ILGenerator encoder, FieldInfo proxy, MethodInfo method, int index)
  125.         {
  126.             var returnsVoid = method.ReturnType == typeof(void);
  127.             var returnsValue = !returnsVoid && method.ReturnType.IsValueType;
  128.             var lookup = typeof(Proxy<T>).GetMethod("Lookup"BindingFlags.Public | BindingFlags.Static);
  129.             var interceptor = proxy.FieldType.GetMethod("Trigger"BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
  130.             var arguments = method.GetParameters().Select(p => p.ParameterType).ToArray();
  131.             encoder.DeclareLocal(returnsVoid ? typeof(object) : method.ReturnType); // return value (local 0)
  132.             encoder.DeclareLocal(typeof (object[])); // parameters (local 1)
  133.             encoder.Emit(OpCodes.Ldarg_0); // this.
  134.             encoder.Emit(OpCodes.Ldfld, proxy); // this._proxy
  135.             encoder.Emit(OpCodes.Ldc_I4_S, index); // index of method to lookup
  136.             encoder.Emit(OpCodes.Call, lookup); // lookup methodinfo by index
  137.             encoder.Emit(OpCodes.Ldc_I4_S, arguments.Length); // set size of parameter array
  138.             encoder.Emit(OpCodes.Newarr, typeof(object)); // create parameter array
  139.             encoder.Emit(OpCodes.Stloc_1); // store to local 1
  140.             for (var i = 0; i < arguments.Length; i++) { // load up parameter array values
  141.                 var argument = arguments[i];
  142.                 encoder.Emit(OpCodes.Ldloc_1); // get ready to add to array (local 1)
  143.                 ConfigureLdc(encoder, i); // index to add to
  144.                 ConfigureLdarg(encoder, i + 1); // get argument (index + 1)
  145.                 if (argument.IsValueType) encoder.Emit(OpCodes.Box, argument); // convert to object if needed
  146.                 encoder.Emit(OpCodes.Stelem_Ref); // push to array
  147.             }
  148.             encoder.Emit(OpCodes.Ldloc_1); // get array
  149.             encoder.Emit(OpCodes.Callvirt, interceptor); // pass stack to method
  150.             if (returnsValue) {
  151.                 encoder.Emit(OpCodes.Unbox_Any, method.ReturnType); // un-object a value
  152.             } else if (!returnsVoid) {
  153.                 encoder.Emit(OpCodes.Castclass, method.ReturnType); // cast to return type
  154.             } else {
  155.                 encoder.Emit(OpCodes.Pop); // discard return value
  156.             }
  157.             encoder.Emit(OpCodes.Ret);
  158.         }
  159.         private static readonly OpCode[] Ldargs = new[] { OpCodes.Ldarg_0, OpCodes.Ldarg_1, OpCodes.Ldarg_2, OpCodes.Ldarg_3 };
  160.         private static void ConfigureLdarg(ILGenerator encoder, int index)
  161.         {
  162.             if (index >= Ldargs.Length) encoder.Emit(OpCodes.Ldarg_S, (short)(index));
  163.             else encoder.Emit(Ldargs[index]);
  164.         }
  165.         private static readonly OpCode[] Ldcs = new[] { OpCodes.Ldc_I4_0, OpCodes.Ldc_I4_1, OpCodes.Ldc_I4_2, OpCodes.Ldc_I4_3, OpCodes.Ldc_I4_4, OpCodes.Ldc_I4_5, OpCodes.Ldc_I4_6, OpCodes.Ldc_I4_7, OpCodes.Ldc_I4_8 };
  166.         private static void ConfigureLdc(ILGenerator encoder, int index)
  167.         {
  168.             if (index >= Ldcs.Length) encoder.Emit(OpCodes.Ldc_I4, index);
  169.             else encoder.Emit(Ldcs[index]);
  170.         }
  171.         #endregion
  172.     }
(This is a huge blob of code I'll explain and break down later)

Let's focus on the example at hand. I want to use this class now to generate proxies for services on the fly. To keep this dynamic I will want to extend the Proxy<T> base class into something like this:

  1.     public class ServiceLogger<T> : Proxy<T> where T : class
  2.     {
  3.         public T Service { get { return Instance; } }
  4.         protected ILogger Logger { getprivate set; }
  5.         public ServiceLogger(T service, ILogger logger) : base(service)
  6.         {
  7.             Logger = logger;
  8.         }
  9.         protected override object OnCall(MethodInfo method, object[] parameters)
  10.         {
  11.             try {
  12.                 return base.OnCall(method, parameters);
  13.             } catch (Exception ex) {
  14.                 Logger.Fatal("{0}.{1} failed : with {2}",
  15.                     method.DeclaringType.Name,
  16.                     method.Name,
  17.                     string.Join(", ", parameters));
  18.                 throw;
  19.             }
  20.         }
  21.         protected override void AfterCall(MethodInfo method, object[] parameters, object result)
  22.         {
  23.             Logger.Info("{0}.{1} called : with {2} : returning {3}",
  24.                 method.DeclaringType.Name,
  25.                 method.Name,
  26.                 string.Join(", ", parameters),
  27.                 result);
  28.         }
  29.     }
Now wherever I am instantiating a service I will simply wrap it with a ServiceLogger<T> and use the ServiceLogger<T>.Service in place of my service. Any code with a dependency on a service of type T will not know the difference between the proxy and the real service and so will not have to be altered.

Consider this:

  1.             ILogger logging;
  2.             IMyService myServiceInstance = new MyService();
  3.             ServiceLogger<IMyService> proxyLogger = new ServiceLogger<IMyService>(myServiceInstance, logging);
  4.             IDependentCode willBeLogged = new DependentCode(proxyLogger.Service);
  5.             IDependentCode wontBeLogged = new DependentCode(myServiceInstance);

The "willBeLogged" and the "wontBeLogged" objects both have the same dependency satisfied. One with a proxy, and the other with the direct service. The one with the proxy will have all of its calls to the proxy logged without having to change anything in the "DependentCode" class.

How it works:

All the code you write in .NET eventually becomes IL (Intermediate Language) when it is compiled. Even though you've written your application in C#, your application is "thinking" in IL (well, not really). Therefore you can't directly tell your application to just run a block of dynamically generated C# code at run-time without some kind of other service to compile your code down into IL. Fortunately for you there is no need to seek the services of a compiler because the .NET framework provides you with the ability to write your own IL.

The first thing you'll need to do in order to start building your own dynamic types is create a dynamic assembly in which to store it. As it is, all of the assemblies in your application are loaded into memory from DLLs and the like. Once an assembly is loaded into your AppDomain you will no longer be able to edit it. So you need to expect that each dynamic Type that you want to create will need to be housed in its own dynamic assembly.

Because of this, if you are not careful, you will have a memory leak as you create more and more dynamic types and will need to make sure that you are only creating new types when necessary. For this I have added a static field to the base Proxy<T> class that holds the dynamic type which is then generated in the static constructor. Normally I avoid adding static fields to generic classes because a new value is generated for each "T" used, however in this case it is exactly what I want.

  1.     public abstract class Proxy<T> where T : class
  2.     {
  3.         protected static readonly Type InstanceType;
  4.         ...
  5.         static Proxy() {
  6.             ...
  7.             InstanceType = Generate();
  8.         }
Now in the instance constructor I simply construct an instance of the type referenced by the static InstanceType field. In a single-threaded environment this will be enough to prevent any leaks. (maybe also in multi-threaded environments?)

The "Generate()" method will create a dynamic type that inherits the "T" interface. The dynamic type will be given a private _proxy field that will reference the owning "Proxy<T>" instance. Each method on the dynamic class will then call the "_proxy.Trigger(...)" method with the appropriate information. The "Trigger" method will call the "BeforeCall", "OnCall", and "AfterCall" virtual methods which can then be overridden by your own subclass to perform whatever interception actions you want.

When generation is complete the dynamically created type resembles a class that would look something like this:

  1.     public class GeneratedProxyClass : IFace
  2.     {
  3.         private Proxy<IFace> _proxy;
  4.         public GeneratedProxyClass(Proxy<IFace> proxy) { _proxy = proxy; }
  5.         public string MethodA(int arg1, int arg2)
  6.         {
  7.             var methodInfo = Proxy<IFace>.Lookup(1);
  8.             var parameters = new object[] { arg1, arg2 };
  9.             return (string)_proxy.Trigger(methodInfo, parameters);
  10.         }
  11.         public void MethodB(string value)
  12.         {
  13.             var methodInfo = Proxy<IFace>.Lookup(2);
  14.             var parameters = new object[] { value };
  15.             _proxy.Trigger(methodInfo, parameters);
  16.         }
  17.     }
The rest is pretty straight-forward even though it doesn't seem so. If you take a peek into the "Generate" method you will see the following steps taken:
  • Create a dynamic Assembly in the current AppDomain
  • Create a dynamic Module in the dynamic Assembly
  • Create a dynamic Type in the dynamic Module
  • Create Fields, Properties, and Methods in the dynamic Type
  • "Build" the new System.Type
Defining a member on a dynamic type is as easy as ".DefineField", ".DefineMethod", or ".DefineProperty". Obviously underlying methods won't magically know what to do when they are invoked. This is where all the IL encoding comes in.

I'm not, however,  going to dive into how to write functionality with IL in this post. My own understanding of how to write IL is very basic and most of that has come from compiling assemblies and looking at what the compiler generates. Nevertheless, I have made sure to leave comments on each Emit statement to help explain what's happening. You can see these in the "ConfigureCall" method.

Enjoy!



Did you like this post?
Let me know:   http://markonthenet.com/contact.htm

Monday, March 24, 2014

client-time.js


This was another experiment of mine to solve a problem that has already been solved probably many times. My goal in doing this is to learn from coming up with my own solution and try to make it a little better than what's out there. I have decided that when I do this it warrants a blog post, at the very least, for those who are unfortunate enough to stumble upon my undocumented work of mystery.

What It Be

So now we have client-time.js. When I say my goal was to make it "better" realize that this term is subjective. In this case I was not trying to best the performance of the other solutions I found. I wanted to make a plugin that would translate dates and times from a server-rendered page to the timezone of the client rendering the page that had the following improvements:
  • Easier to read code (this is also subjective)
  • Adaptable format strings to match the server-side strings
The idea behind this is that the same string that is used to format a date will ideally be the same string required to parse a date. The process we are trying to support here is rendering a page with all dates and times in UTC, but having them seen by the end-user in his/her own timezone.

My Solution

Keep in mind that I wanted to make this easy to adapt to other format string schemas out there. So the first thing I did was try to break down the process of both parsing and formatting a date. What I came up with was 2 steps consisting of 2 parts each:
  • pattern & reader
  • parser & mapper
Writing this now in a blog makes me realize my naming conventions are off and should be fixed at some point...

The first step is to read a UTC time based on a formatter. For example if I am given a format string looking something like this: "yyyy MM dd HH:mm" I expect the time I am given to look something like this: "1999 12 20 15:32". 

To make this possible in the plugin I've paired the pattern-item for reading (yyyy) with a regex pattern for parsing (/\d{4}/) and now I am able to convert a format string into a regex statement for reading. What I end up with is something like this: /(\d{4}) (\d{2}) (\d{2}) (\d{2}):(\d{2})/. 

Once this is done all I have to do is take the information from the regex groups in the match and map it to the appropriate UTC setters on a javascript Date object. Unfortunately in javascript there are no named groups so prior to converting the format string to a regular expression I must make an index map letting me know what regex groups correspond with which pattern items. Anyways, to accomplish this I have grouped a function I am calling a "mapper" with each "pattern"/"parser" pair.

Finally all that is left to do is read the LOCAL values from the Date object and replace each part of the format string with the appropriate values. With this my formatter group grows to 4 items, the final being a function that takes a value from the Date object and returns it in the appropriate format.

What we get is something like this:

  1. var formatters = [
  2.     { pattern: 'yyyy', parser: '\\\\d{4}',              reader: function () { return leadZeros(this.year, 4); },              mapper: function (value) { this.setUTCFullYear(parseInt(value)); } },
  3.     { pattern: 'yy',   parser: '\\\\d{2}',              reader: function () { return leadZeros(this.year, 2); },              mapper: function (value) { this.setUTCFullYear(parseInt(getCentury() + value)); } },
  4.     { pattern: 'MMMM', parser: longMonths.join('|'),  reader: function () { return longMonths[this.month]; },               mapper: function (value) { this.setUTCMonth(indexOf(longMonths, value)); } },
  5.     { pattern: 'MMM',  parser: shortMonths.join('|'), reader: function () { return shortMonths[this.month]; },              mapper: function (value) { this.setUTCMonth(indexOf(shortMonths, value)); } },
  6.     { pattern: 'MM',   parser: '\\\\d{2}',              reader: function () { return leadZeros(this.month, 2); },             mapper: function (value) { this.setUTCMonth(parseInt(value) - 1); } },
  7.     { pattern: 'M',    parser: '\\\\d{1,2}',            reader: function () { return this.month; },                           mapper: function (value) { this.setUTCMonth(parseInt(value) - 1); } },
  8.     { pattern: 'dddd', parser: longDays.join('|'),    reader: function () { return longDays[this.dayOfWeek]; },             mapper: function (value) { } },
  9.     { pattern: 'ddd',  parser: shortDays.join('|'),   reader: function () { return shortDays[this.dayOfWeek]; },            mapper: function (value) { } },
  10.     { pattern: 'dd',   parser: '\\\\d{2}',              reader: function () { return leadZeros(this.day, 2); },               mapper: function (value) { this.setUTCDate(parseInt(value)); } },
  11.     { pattern: 'd',    parser: '\\\\d{1,2}',            reader: function () { return this.day; },                             mapper: function (value) { this.setUTCDate(parseInt(value)); } },
  12.     { pattern: 'HH',   parser: '\\\\d{2}',              reader: function () { return leadZeros(this.hour24, 2); },            mapper: function (value) { this.setUTCHours(parseInt(value)); } },
  13.     { pattern: 'H',    parser: '\\\\d{1,2}',            reader: function () { return this.hour24; },                          mapper: function (value) { this.setUTCHours(parseInt(value)); } },
  14.     { pattern: 'hh',   parser: '\\\\d{2}',              reader: function () { return leadZeros(this.hour12, 2); },            mapper: function (value) { this.setUTCHours(parseInt(value) % 12); } },
  15.     { pattern: 'h',    parser: '\\\\d{1,2}',            reader: function () { return this.hour12; },                          mapper: function (value) { this.setUTCHours(parseInt(value) % 12); } },
  16.     { pattern: 'mm',   parser: '\\\\d{2}',              reader: function () { return leadZeros(this.minute, 2); },            mapper: function (value) { this.setUTCMinutes(parseInt(value)); } },
  17.     { pattern: 'm',    parser: '\\\\d{1,2}',            reader: function () { return this.minute; },                          mapper: function (value) { this.setUTCMinutes(parseInt(value)); } },
  18.     { pattern: 'ss',   parser: '\\\\d{2}',              reader: function () { return leadZeros(this.second, 2); },            mapper: function (value) { this.setUTCSeconds(parseInt(value)); } },
  19.     { pattern: 's',    parser: '\\\\d{1,2}',            reader: function () { return this.second; },                          mapper: function (value) { this.setUTCSeconds(parseInt(value)); } },
  20.     { pattern: 'o',    parser: 'th|st|nd|rd',         reader: function () { return this.ordinal; },                         mapper: function (value) { } },
  21.     { pattern: 'TT',   parser: 'AM|PM',               reader: function () { return this.ampm.toUpperCase(); },              mapper: function (value) { pmAdjust(this, value); } },
  22.     { pattern: 'T',    parser: 'A|P',                 reader: function () { return this.ampm.toUpperCase().substr(0, 1); }, mapper: function (value) { pmAdjust(this, value); } },
  23.     { pattern: 'tt',   parser: 'am|pm',               reader: function () { return this.ampm.toLowerCase(); },              mapper: function (value) { pmAdjust(this, value); } },
  24.     { pattern: 't',    parser: 'a|p',                 reader: function () { return this.ampm.toLowerCase().substr(0, 1); }, mapper: function (value) { pmAdjust(this, value); } }
  25. ];
Instructions For Use

Here is how to use it:

First you will need to have both jQuery.js and client-time.js referenced by your page.

  1. <head>
  2.     <meta charset="utf-8" />
  3.     <title></title>
  4.     <script src="scripts/jquery.js"></script>
  5.     <script src="scripts/client-time.js"></script>
  6. </head>
Once that is done anywhere you want to display a date/time on your page make sure to wrap it in its own element. A span, or div would suffice.

  1.     <p>
  2.         A long time ago it was <span>1999 April 11, 12:00 pm</span>
  3.     </p>
Next we need to inform "client-time.js" what format string we are using. I have wired this up to use both a config object or data attributes. You will most likely only ever want the data attributes. So now the previous markup should look something like this:

  1.     <p>
  2.         A long time ago it was <span data-time-format="yyyy MMMM d, hh:mm tt">1999 April 11, 12:00 pm</span>
  3.     </p>
Finally we just need to let client-time.js know which elements need localizing

  1. $('[data-time-format]').clientTime();
Now when your page is shown in the browser client-time will read the date in your span as UTC, convert it to your machine's local time, and update the time appropriately using the same format.

My Disclaimers





Saturday, February 8, 2014

Inline Razor Templates

Haven't heard of the System.Web.WebPages.HelperResult? Maybe you have, but you really don't know what it is. Don't worry, you're not alone.

So what is it? 

Simply put it is the key to processing inline Razor templates. What that means is you can put parsed and fully intellisensed blocks of Razor (html) markup directly in your HtmlHelper extension methods, view model constructors, and even view model properties. These can then be read, processed, and rendered seamlessly by your code without any tedious processing or setup.

Look at this sample HtmlHelper extension method which utilizes an inline Razor template:

  1. <div id="my-content">
  2.     @Html.DoSomething(
  3.         @<div>
  4.             Here is some <em>inline</em> html content.
  5.         </div>)    
  6. </div>
The #my-content content shown here is actually passed to the DoSomething method which can then be processed and rendered to an MvcHtmlString and then rendered to your final web page.



So WHY would I want that?
Let's look at a very common approach to Razor view development in the wild today:

  1. <div>
  2.     La la la<br />
  3.     I'm a block of happy HTML...<br />
  4.     But wait...<br />
  5.     What's that inside me???<br />
  6.     
  7.     @Html.MethodOfUnknownHtmlGeneration("guess-what-i-am"new Dictionary<stringobject> {
  8.         {"and-what-i-am""or-what-i-do"},
  9.         {"I-could-mean-anything""or-render-anything"}
  10.     })
  11.     
  12.     <strong>OMG!!!! HALP!!!</strong>
  13. </div>
MAYBE if I were the person who wrote this HtmlHelper extension method I would know what kind of chaos this would put on my final web page when it is rendered. OR maybe I work on a team and one of my co-workers wrote this. What then? I have to try to find it used in the application somewhere in order to know how it should be wired up. Or I might even have to find the code for this method to try and figure out what it does and what kind of parameter inputs it expects.

We could even think a year ahead when I have to come back to this application and troubleshoot something that isn't working on the page. Maybe that something is a piece of javascript functionality that interfaces with this mysteriously generated HTML markup. I run a search on my code to find where that HTML is at, but it doesn't show up anywhere!

What if I'm not even a developer on the team - what if I'm a designer-css guy? Or what if I am the javascript guy that doesn't know or work with .NET?



**The Situation**

Let's say I have a common formatting for popover content that will "hover" over its surrounding content. Basically everywhere I want a floating notation or tooltip I need to reproduce this structure and leave it to the CSS and javascript to do the rest.

Assuming my team are Bootstrap fans my markup might look something like this:

  1. <div class="popover right">
  2.     <div class="arrow"></div>
  3.     <h3 class="popover-title">My Popover Title</h3>
  4.     <div class="popover-content">
  5.         <strong>This is my popover content:</strong><br />
  6.         <p>
  7.             I need to be able to format this content
  8.             and somehow get it appropriately wrapped
  9.             with all this Bootstrap goodness...
  10.         </p>
  11.     </div>
  12. </div>

**The Problem**

As it turns out I have to reproduce this structure a few hundred times in the application. What I don't want to do is have to remember this structure or continually reproduce this part of the formatting:

  1. <div class="popover right">
  2.     <div class="arrow"></div>
  3.     <h3 class="popover-title"></h3>
  4.     <div class="popover-content">
  5.     </div>
  6. </div>
So I need a solution that will somehow produce this structure for me, yet allow me to insert my content into the structure appropriately.
As a typical .NET developer my first thought might be something like this...

  1.         public static MvcHtmlString Popover(this HtmlHelper helper, string title, string content)
  2.         {
  3.             var markup = string.Format(@"
  4.                 <div class=""popover-content"">
  5.                     <div class=""arrow""></div>
  6.                     <h3 class=""popover-title"">{0}</h3>
  7.                     <div class=""popover-content"">{1}</div>
  8.                 </div>", title, content);
  9.             return new MvcHtmlString(markup);
  10.         }
Which would look like this in my markup:

  1. @Html.Popover("My Popover Title""Here is some popover content")
But for reasons previously stated I don't want this markup hidden in a formatted string somewhere. Fortunately, as a typical MVC developer, I have learned that I can simply just make a partial which takes a view model. This can either be rendered using the existing .Partial() HtmlHelper extension method or called from a custom method.

The ViewModel:

  1.     public class PopoverViewModel
  2.     {
  3.         public string Title { getset; }
  4.         public string Content { getset; }
  5.     }
The View:

  1. @model MyApplication.Models.PopoverViewModel
  2. <div class="popover-content">
  3.     <div class="arrow"></div>
  4.     <h3 class="popover-title">
  5.         @Model.Title
  6.     </h3>
  7.     <div class="popover-content">
  8.         @Model.Content
  9.     </div>
  10. </div>
The Usage:

  1. @Html.Partial("_Popover"new PopoverViewModel {
  2.     Title = "This is my title",
  3.     Content = "This is my content"
  4. })
But as shown in my original markup, the content needs to be formatted. I need to, without some ridiculous string concatenation, get HTML formatting in there. This is difficult to do when only being able to pass a set of plain ol' strings into a partial.

**The Solution**

This is where inline Razor templates shine. First let's change the view model a bit:

  1.     public class PopoverViewModel
  2.     {
  3.         public string Title { getset; }
  4.         public Func<objectHelperResult> Content { getset; }
  5.         public MvcHtmlString RenderContent()
  6.         {
  7.             // Render the template
  8.             var rawHtml = Content(null).ToHtmlString();
  9.             // Send it to the view
  10.             return new MvcHtmlString(rawHtml);
  11.         }
  12.     }
Next let's update the partial view:

  1. @model MyApplication.Models.PopoverViewModel
  2. <div class="popover-content">
  3.     <div class="arrow"></div>
  4.     <h3 class="popover-title">
  5.         @Model.Title
  6.     </h3>
  7.     <div class="popover-content">
  8.         @Model.RenderContent()
  9.     </div>
  10. </div>
Now we can update our usage:

  1. @Html.Partial("_Popover"new PopoverViewModel {
  2.     Title = "This is my title",
  3.     Content = @<div>
  4.                    <strong>This is my popover content:</strong><br />
  5.                    <p>
  6.                        I need to be able to format this content
  7.                        and somehow get it appropriately wrapped
  8.                        with all this Bootstrap goodness...
  9.                    </p>
  10.                </div>
  11. })
The div with its content will be passed to the Content property of the view model. The signature Razor will give you when it sees an inline template is a Func<object, HelperResult>. To render the template into a plain string containing the HTML you only have to call the delegate to obtain the HelperResult and then invoke the .ToHtmlString() method off of the result.

There are dozens of situations this pattern can be applied to: auto-localization of view content and java interaction wireups to name a couple, but the inline template still has a couple more secrets to reveal...



So the first thing you'll probably notice about Razor inline templates is that horrible Func<object, HelperResult> signature. The template is not actually a Func, it's just a delegate which happens to be mappable to a Func. It should go without saying that this is not a very friendly signature and so reduces maintainability as it is not immediately evident what exactly a Func<object, HelperResult> is supposed to be. A year after writing some code with this signature you might have to do some searching to remember what is expected here.

The cool thing about this being a delegate is that it can be mapped to any defined delegate with a matching signature. This means I can make this look however I want with virtually a single line of code. Try adding the following as a .cs file to your project:

  1. namespace System.Web.WebPages
  2. {
  3.     public delegate HelperResult RazorTemplate(object item);
  4.     public delegate HelperResult RazorTemplate<T>(T item);
  5. }
Instead of a Func<object, HelperResult> signature I can use one of these delegate signatures.
Now my intellisense will look something like this:








Did you notice the "item" parameter in the signature? Like the "Model" reference in your regular Razor views, you will have access to the parameter passed to the template using "@item".

  1. @Html.MyHelperMethod(@<div>
  2.                           Here is the value of item: "@item"
  3.                       </div>)
This will be most useful when building a helper method or template to support the display of an item collection. Let's say I want to make a custom combo-box control with templated select-items:

The ViewModel:

  1.     public class ComboBoxViewModel
  2.     {
  3.         public string Name { getset; }
  4.         public List<object> Items { getset; }
  5.         public RazorTemplate ItemTemplate { getset; }
  6.         public MvcHtmlString RenderItem(object item)
  7.         {
  8.             return new MvcHtmlString(ItemTemplate(item).ToHtmlString());
  9.         }
  10.     }
The View:

  1. @model MyApplication.Models.ComboBoxViewModel
  2. <div class="combo-box">
  3.     <input type="hidden" name="@Model.Name"/>
  4.     <div class="selected-item"></div>
  5.     <ul class="item-menu">
  6.         @foreach (var item in Model.Items) {
  7.             <li>
  8.                 @Model.RenderItem(item)
  9.             </li>
  10.         }
  11.     </ul>
  12. </div>
The Usage:

  1. @Html.Partial("_ComboBox"new ComboBoxViewModel {
  2.     Name = "SelectedValue",
  3.     Items = new List<object>{"Item 1""Item 2""Item 3"},
  4.     ItemTemplate = @<strong><em>@item</em></strong>
  5. })
NOTE: By default the parameter passed into an inline Razor template will always be named item. Changing the name of the parameter in the signature will have no effect on the value's name in the template. It should also be noted that because the parameter in the template is inline to your regular view, any variable generated in your view with the name item may cause warnings or errors and conflict with your template.


It should also probably be mentioned here that an inline Razor template can not support additional inline templates. For example if I were to use the Popover template from earlier in this post and try to render a custom combo-box control inside it, I would get a compile error because the "ItemTemplate" property could not be set inside the Popover template.

There is, however, a reasonable workaround for this limitation: Razor helper methods can be written outside of the inline template and then called from inside it. For example:

  1. @Html.Partial("_Popover"new PopoverViewModel {
  2.     Content = @<div>
  3.                    Popover content with a templated
  4.                    ComboBox inside of it!
  5.                    @RenderComboBox("value"new List<object>{"Item 1""Item 2"})
  6.                </div>
  7. })
  8. @helper RenderComboBox(string name, List<object> items) {
  9.     @Html.Partial("_ComboBox"new ComboBoxViewModel {
  10.         Name = name,
  11.         Items = items,
  12.         ItemTemplate = @<strong>@item</strong>
  13.     })
  14. }





Did you like this post?
Let me know: http://markonthenet.com/contact.htm