Dynamic compilation in ASP.NET

We all know about magic App_Code folder. Just drop class file in there and it will become a part of the web application. This is fine for scripts like PHP or "classic" ASP (VB script), but C# is strongly typed compiled language. How App_Code works? As any magic, mostly smoke and mirrors. Behind the scene, ASP.NET will create App_Code.dll and merge it with main application assembly at run time. This simple trick gives us best of both worlds - dynamism of scripting languages (ok, to the point) and all the good stuff coming with strong typing and compilation (whatever they are).

App_Code also gives us nice extensibility point. BlogEngine uses it to dynamically instantiate extensions and load them on application start, so that you can simply add class marked with extension attribute to this folder and your extension is up and running, no need to re-compile application or even restart web server - ASP.NET will take care of it. Nicely done! But recently I ran into topic on BE forum where VB.NET programmer asked if he can write extensions in VB. Good question! Not really, you can't mix C# and VB in App_Code. At least, not out of the box. But if we build a little more on top of App_Code magic - anything is possible.

Lets start by splitting App_Code in two subdirectories - CS_Code and VB_Code. For ASP.NET be aware of what we are doing, make this change to compilation section in web.config:

<compilation defaultLanguage="c#" debug="true">
  <codeSubDirectories>
    <add directoryName="CS_Code"/>
    <add directoryName="VB_Code"/>
  </codeSubDirectories>
</compilation>

If you look at solution in Visual Studio project explorer, you'll notice that new folders show up as "special" ASP.NET folders.

vbx.png

Now you can put .cs files in CS_Code and .vb files in VB_Code and ASP.NET will generate both C# and VB DLLs and merge them into application assembly. So far so good. Little problem is that BlogEngine makes use of App_Code in a few places and expects single code assembly. Lets fix it. First of all, we create new static method in Utility class that returns ListArray of all code assemblies, and then use this method where BlogEngine has to deal with App_Code.

public static ArrayList CodeAssemblies()
{
  ArrayList codeAssemblies = new ArrayList();
  try
  {
    string assemblyName = "__code";
    CompilationSection s = (CompilationSection)WebConfigurationManager.GetSection("system.web/compilation");
    if (s != null &amp;&amp; s.CodeSubDirectories != null &amp;&amp; s.CodeSubDirectories.Count > 0)
    {
      for (int i = 0; i < s.CodeSubDirectories.Count; i++)
      {
        assemblyName = "App_SubCode_" + s.CodeSubDirectories[i].DirectoryName;
        codeAssemblies.Add(Assembly.Load(assemblyName));
      }
    }
    else
    {
      Type t = Type.GetType("Mono.Runtime");
      if (t != null) assemblyName = "App_Code";
      codeAssemblies.Add(Assembly.Load(assemblyName));
    }
  }
  catch(System.IO.FileNotFoundException){/*ignore - code directory has no files*/}
  catch (Exception e) { throw; }
  return codeAssemblies;
}

This will return all assemblies compiled from App_Code. If you add Iron Python or J# - good to go. All that left is to make few more changes to client code that will make use of this method and we done. I don't want to put whole project for download, but if you interested let me know and I'll send it to you.

About RTUR.NET

This site is all about developing web applications with focus on designing and building open source blogging solutions. Technologies include ASP.NET Core, C#, Angular, JavaScript and more.