Dynamically Executing Code in .NET

Dynamically Executing Code in .NET

xecuting code dynamically at runtime is a powerful tool to allow users to customize applications after deployment. .NET provides all the tools that make it possible to build code on the fly, compile it and run it dynamically.

I come from an xBase background and have been using Visual FoxPro for many years. One of the nice features of xBase is the ability to dynamically execute code in applications. In Visual FoxPro you can execute code from a string simply by calling EXECSCRIPT() or executing a single expression by calling EVALUATE(). In other environments, however, dynamic code execution is considerably more difficult to achieve, especially in true compiled languages that make it impossible to run code on the fly directly. Those tools have to rely on external tools like the Active Scripting control from Microsoft or other third-party parsers.

Dynamic code execution is a powerful tool for extending applications and allowing customization of an application after it has shipped. Plug-ins and other end-user extensibility features almost exclusively rely on the ability to execute code after formal compilation of the application. Scripting engines and template formatting use dynamic code when it’s necessary to mix data with the display output. A good example of this is ASP scripting, which basically is a sophisticated script parser that executes code on the fly. (See Sidebar: Assemblies and Namespaces)

.NET provides full control over dynamic code execution natively via the .NET SDK classes. However, the process is not nearly as trivial as it is in Visual FoxPro. It requires a fair amount of code to accomplish something similar and you need to know how .NET loads assemblies into the application. In exchange, .NET provides a lot of flexibility in using dynamic code with full control over the entire process including compilation, error reporting, loading objects, and controlling the environment.

Compiling Code on the Fly
.NET provides powerful access to the IL code generation process through the System.CodeDom.Compiler, Microsoft.Csharp, and Microsoft.VisualBasic namespaces. In these namespaces you’ll find the tools that allow you to compile an assembly either to disk or into memory. You also need the Reflection namespace as it contains the tools to invoke an object and its methods once you’ve compiled the object.

In the following example I’ll demonstrate how to execute an arbitrary block of code. The code is free standing and has no dependencies. The process to execute this code dynamically involves the following steps:

  1. Create or read in the code you want to execute as a string.
  2. Wrap the code into fully functional assembly source code, which includes namespace references (using commands), a namespace, and a class that is to be invoked.
  3. Compile the source code into an assembly.
  4. Check for errors on compilation.
  5. Use the assembly reference to create an instance of the object.
  6. Call the specified method on the instance reference returned using Reflection.
  7. Handle any return value from the method call by casting into the proper type.
Figure 1: This sample form demonstrates how to execute code from the top text box dynamically.

The example shown in Listing 1 demonstrates the code to perform these steps. Figure 1 shows an example of the form that utilizes this code. Please note that there’s only minimal error handling provided in most code snippets for brevity’s sake.

The code begins by creating various objects that are required for compilation. It then uses the CompilerParameters object to add any assembly references required during compilation. These are the physical DLLs that are required and are the equivalent of what you add in the VS.NET project References section. Note that it’s very important that every reference is included or you will get compiler errors. This is one of the tricky parts about dynamic code compilation as this step must occur in your application code. Here the Windows Forms assemblies are included to allow using the MessageBox object to display output.

The next step is to generate the complete source code for an assembly. This example makes a few assumptions about the code in that it presets the method parameter and return value signature as:

   public object DynamicCode(params object[] Parameters);

So a block of code MUST return a value of type object or null. It can also accept any number of parameters that can be referenced via the Parameters collection. A simple example of a string to execute might be.

   string cName = "Rick";   MessageBox.Show("Hello World" + cName);   return (object) DateTime.Now;

If you wanted to access parameters dynamically instead you might do this:

   string cName = (string) Parameters[0];

Note that you should cast parameters explicitly to the specific type since the object parameter is generic. You can also return any value as long as you cast it to an object type.

This code is now fixed up into an assembly by adding namespace, class, and method headers. The final generated code that gets compiled looks like this:

   using System.IO;   using System;   using System.Windows.Forms;   namespace MyNamespace   {      public class MyClass      {         public object DynamicCode(            params object[] Parameters)         {            string cName = "Rick";            MessageBox.Show("Hello World" + cName);            return (object) DateTime.Now;         }      }   }

This code can now be compiled into an assembly by using the CompileAssemblyFromSource() method of the CodeCompiler. The CompilerResults object receives information about the result. You can retrieve compile errors via the HasErrors property and Error collection. If there were no errors you get a reference to the Assembly in CompiledAssembly property from which you can call CreateInstance() to create a live instance of the MyClass class.

This is where Reflection comes in: Because we’ve basically created a .NET type on the fly, the object reference and all method access must occur dynamically rather than through direct referencing. The compiler has no idea of the type at compile time, but must delay creation and type info until runtime. So when I called CreateInstance an object of type Object is returned and I have to use Reflection and InvokeMember to call a method on the object indirectly.

The actual call to the object method then proceeds and returns a reference to a generic object type (much like a variant). This type can contain data of any type and I suggest that you immediately cast the return type to an explicit type if possible. Notice also the error handling around the InvokeMember call?this is fairly crucial as it protects the calling application from any runtime errors that occur in the dynamic code.

I’ve demonstrated this technique by using Visual C# .NET as the dynamic code language here. You can also use Visual Basic by using the Microsoft.VisualBasic namespace and using the VBCodeProvider class instead to instantiate the loCompiler object. Of course, you’d have to change the assembly source code to VB syntax in addition to the actual dynamic code I show here. The class I’ll present later provides the ability to execute both C# and VB code by setting a language property.

As I mentioned at the start of this article, .NET provides a lot of functionality and control over the compile and execution process. However, this is a lot of code to have to integrate into an application each time you want to execute dynamic code. To make life easier I’ve created a class that simplifies the process considerably and aids in handling errors and debugging the code should errors occur.

Understanding How .NET Loads Code
Before I dive into the dynamic code execution class I need to discuss the important subject of application domains and how they behave when assemblies are loaded. Application domains are the highest level isolated instances of the .NET runtime that host application code and data. Assemblies get loaded into a specific application domain and execute and use resources in it.

When you normally run a .NET application, .NET simply loads each assembly on your references list into the application’s primary Application Domain (see Sidebar: What’s an Application Domain?). No problem there?you want all code to load into this domain and stay loaded there. So if there’s code that dynamically uses the JIT compiler to compile code, the code will remain in the AppDomain cached and compiled so only the first access to it is relatively slow.

So far, so good. But here’s the rub in our dynamic code execution scheme: Application domains load assemblies, but they cannot unload them! If you’re only loading a handful of assemblies this won’t be a problem, but often-times when you run dynamic code it’s quite possible that you will create a lot of snippets that need to run and compile independently then essentially throw them away. For example, I have a Desktop application that uses templates on disk to hold HTML mixed with .NET code. The application merges the content of a database record (actually an object view of it) into the template. The documents are merged on the fly and only on an as needed basis. This system can have thousands of entries and almost every page has to be compiled separately.

If you run the demo above in a loop for 10-20 times you will notice that memory usage increases with each instance of creating and releasing an assembly. The process consumes a few K each time depending on the size of the assembly and its related referenced assemblies. Once loaded, none of that space can be unloaded again if the assembly is loaded into the current application’s AppDomain.

So what do you do? Unfortunately there’s no simple answer?only a convoluted one. The answer is to create a new application domain and load your dynamic assemblies into that. You can have a choice of loading into this AppDomain, running your code, and unloading it, or alternately you can run all of your dynamic code into the new domain and kill it later or when it reaches a certain number of executions or other metric. Unfortunately this process is not trivial and requires that you use an intermediary proxy object that can invoke a method in a remote AppDomain without referencing the object in the local application domain in any way (which again would lock the assembly into the local AppDomain). The process here is essentially the same as invoking a remote object over the network along with all the same complications.

Creating Code in Alternate AppDomains
Loading an assembly and creating a class instance from it in a different application domain involves the following steps:

  1. Create a new AppDomain.
  2. Dynamically create the dynamic assembly and store it to disk.
  3. Create a separate assembly that acts as an object factory and returns an Interface rather than a physical object reference. This assembly can be generic and is reusable but must be a separate DLL from the rest of the application.
  4. Create an object reference using AppDomain::CreateInstance and then call a method to return the remote Interface. Note the important point here is that an Interface not an object reference is returned.
  5. Use the Interface to call into the remote object indirectly using a custom method that performs the passthrough calls to the remote object.

The whole point of this convoluted exercise is to load the object into another AppDomain and access it without using any of the object’s type information. Accessing type information via Reflection forces an assembly to load into the local AppDomain and this is exactly what we want to avoid. By using a proxy that only publishes an Interface your code load only a single assembly that publishes this generic Interface.

For the dynamic code execution class I’m going to create a very simple Interface (shown in Listing 2) that can simply invoke a method of the object.

This Interface is then used to make passthrough calls on the methods of the dynamic object. The code to generate the full assembly looks like this:

   using System.IO;   using System;   using System.Windows.Forms;   namespace MyNamespace   {      public class MyClass :                      MarshalByRefObject,IRemoteInterface      {         public object Invoke(string lcMethod,            object[] Parameters)         {            return this.GetType.InvokeMember(lcMethod,               BindingFlags.InvokeMethod,               null,this,Parameters);         }            public object DynamicCode(            parms object[] Parameters)         {            string cName = "Rick";            MessageBox.Show("Hello World" + cName);            return (object) DateTime.Now;         }      }   }

By doing this we’re deferring the type determination via Reflection into the class itself. Note that the class must also derive from MarshalRefObject, which provides the access to data across application domain boundaries (and .NET Remoting boundaries) using proxies.

In addition to the Interface I’ll show you how to create a proxy loader object that acts as an Interface factory: It creates an instance reference to the remote object by returning only an Interface to the client. Listing 3 shows the code for this single method class that returns an Interface pointer against which we can call the Invoke method across domain boundaries without requiring that you have a local reference to the type information.

This class and the IRemoteInterface should be compiled into a separate, lightweight DLL so it can be accessed by the dynamic code for the Interface. Both the client code and the dynamic code must link to the RemoteLoader.dll as both need access to IRemoteInterface.

To use all of this in your client code you need to do the following:

  1. Compile your DLL to disk?you can’t load the assembly from memory into the other AppDomain unless you run the entire compilation process in the other AppDomain.
  2. Create an AppDomain.
  3. Get a reference to IRemoteInterface.
  4. Call the Invoke method to make the remote method call.

The revised code that loads an AppDomain, compiles the code, runs it, and unloads the AppDomain is shown in Listing 4. Revisions from the previous version are highlighted.

The key differences are loading the AppDomain and how you retrieve the actual reference to the remote object. The critical code that performs the difficult tasks is summarized in:

   RemoteLoaderFactory factory =      (RemoteLoaderFactory) loAppDomain.CreateInstance(      "RemoteLoader",      "Westwind.RemoteLoader.RemoteLoaderFactory")      .Unwrap();      // *** create Interface reference from assembly   object loObject = factory.Create( "mynamespace.dll",      "MyNamespace.MyClass", null );      // *** Cast object to remote Interface,    //     to avoid loading type info   IRemoteInterface loRemote =      (IRemoteInterface) loObject;      // *** Call the DynamicCode method with no parms   object loResult = oRemote.Invoke("DynamicCode",null);

This code retrieves a reference to a proxy. RemoteLoader loads the object in the remote AppDomain and passes back the Interface pointer. The Interface then talks to the remote AppDomain proxy to pass and retrieve the actual data. Because the Interface is defined locally (through the DLL reference), simply call the Invoke() method published by the Interface directly.

Creating an AppDomain, loading assemblies into it, making remote calls, and finally shutting the domain down does incur some overhead. Operation of this mechanism compared to running an assembly in process is noticeably slower. However, you can optimize this a little by creating an application domain only once and then loading multiple assemblies into it. Alternately you can create one large assembly with many methods to call and simply hang on to the application domain as long as needed. Still, even without creating and deleting the domain operation is slower because of the proxy/remoting overhead.

Making Life Easier with wwScripting
There’s a lot of power in all of that code?it shows how much flexibility there is in the .NET Framework, but you certainly wouldn’t want to put all of that code into your application each time you need to execute code dynamically. It’s reasonably easy to abstract all of this code into a class. You can find the code in the wwScript.cs source file and in the Westwind.Tools.Scripting namespace with the wwScripting class.

The class provides the following features:

  • Transparent execution of C# and Visual Basic code
  • Execution in the current AppDomain or via external AppDomains for shutdowns
  • Error handling
  • High level and low level methods

With the class running dynamic code gets a bit easier as shown in Listing 5.

If you want to load the code into a different AppDomain call the CreateAppDomain(“Name”) method before the ExecuteCode() method call.

The class also includes several methods for executing code. For example, ExecuteMethod() allows you to provide a full method including the signature defining parameters and return values. This makes it possible to create properly typed parameters and return values. For example, take a code snippet like this:

   public string Test(string lcName, int x)   {      string cHello;      cHello = lcName;      MessageBox.Show(cHello,"Compiler Demo");      return DateTime.Now.ToString();   }

You can then run with this code:

   string lcResult = (string)   loScript.ExecuteMethod(lcCode,   "Test","rick strahl",x);

Notice that you can access the parameters directly by name in the dynamic code snippet. It’s a little cleaner if you pass parameter and return values this way. You can also pass multiple methods as a string:

   public string Test(string lcName, int x)   {      string cHello;      cHello = lcName;      MessageBox.Show(cHello,"Compiler Demo");      return DateTime.Now.ToString();   }      public string Test2(string lcName, int x)   {      return Test(lcName,x);   }

You can then call the two methods like this:

   string lcResult = (string) loScript.ExecuteMethod(      lcCode,"Test","rick strahl",(int) x);   lcResult =  (string)      loScript.CallMethod(loScript.oObjRef,      "Test2","rick strahl",(int) x);

Note that making the second call is rather more efficient because the object already exists and is loaded. No recompilation or regeneration occurs on this second call.

CallMethod() is one of the lower level methods of the class. With it you can perform each step of the compile process individually. A number of other low level methods are (see Table 1 and Table 2).

Table 1: Low-level methods of the wwScripting object.

Low Level Method




Compiles an assembly and holds an internal pointer to theassembly object (only if locally loaded?AppDomains are handled from disk).

Source code


Creates an instance of the compiled code either in thelocal or a remote AppDomain. Sets the oObjRef property with the reference tothe object or Interface.

Uses internal references to the Assembly or the name of the DLL file to loadinto an AppDomain.


Executes a method by name using the oObjRef pointer. Knowsabout local or remote AppDomain.


The method to call.

A variable list of parameters from 0 to n.


Creates an AppDomain and forces CreateInstance andCallMethod to use that domain to load and execute code in.


Name of the domain


Cleans up and releases references.


Table 2: Low-level properties of the wwScripting object.




Error flag that should be checked after making callsbefore using any results.


Contains error information either after compiling orrunning code.


Determines whether the code that is finally compiled issaved. Full assembly source code.


Set before compilation if lSaveSourceCode is true.


After a successful method execution (or after callingCreateInstance) this property contains an instance of the dynamic object.


Name of the namespace that the code is generated into.This is used to generate the assembly and then used again when the class isinstantiated to reference the type.


Same as cAssemblyNamespace


Determines if certain assemblies and namespaces are loadedby default. Loads System, System.IO, System.Reflection.

Building an ASP-like Script Parser

Figure 2: The wwASPScripting class in conjunction with the wwScripting class can run C#-based script code that works with basic ASP syntax.

To show you how useful dynamic code execution is and how little code it takes to build powerful functionality, I’ve included another class called wwASPScripting and a small sample app that demonstrates it with the source code. It’s basically a simple ASP template parser you can use in your own non-Web applications. Although ASP.NET has a powerful script parser, it unfortunately only works with Web interfaces, not for general code (See Sidebar: Why Do We Need a Script Parser?).

It isn’t difficult to build a basic parser that can handle this task. Take a look at Figure 2, which shows both the generated C# code and the output.

If you look closer at Figure 2 you can see what happens behind the scenes. The HTML template is turned into C# source code. The parser simply runs through the page finding all of the <% tags and inserts the appropriate Response.Write() or Response.oSb.Append() commands. Non-tagged text is expanded into strings delimited with quotes. As a special case the <%@ %> directive handles Assembly and Import keywords to allow importing namespaces and assembly files for linking. To include assemblies and namespaces you can use directives like this:

   <%@ Assembly name="System.Windows.Forms.dll"%>   <%@ Import namespace="System.Windows.Forms"%>

I put together a separate class, wwASPScripting, to handle parsing strings into C# code. It’s only a demo and provides rudimentary functionality?a first stab. This parser also only handles C# code at this time as VB code would require generating code quite differently and my VB skills lack a bit in that department.

Figure 6 shows the code to accomplish parsing a template page.

The key and new feature of this code is the ParseScript method that basically turns the ASP-style code seen in Figure 2 into runnable C# code that is then passed to the wwScripting class to dynamically execute.

The wwASPScripting class is only a first shot and doesn’t do more than parse. It has a private implementation of a Response object that is used to write output into the output stream. The wwASPScripting class natively uses a string builder to allow output to be sent to a string or stream. The ParseScript method is rather short and you can review the source code of how the code conversion is performed in the wwAspScripting.cs source file included with the downloadable code.

You’re So Dynamic
It is interesting how .NET allows you to run dynamic code?essentially it provides you all the tools that a compiler uses to generate an executable. If you want to get even more low level you can use the System.Reflection.Emit namespace to generate IL level code directly. I am amazed how little overall code this mechanism requires even if coming up with that code wasn’t quite so trivial, digging through the .NET docs (and help from several people on various newsgroups!). It’s also interesting to see how to apply this technology and build a custom script parser with even less code. The process is relatively easy and straightforward once you can use the wrapper classes. Well, easy may be a little overstated. This whole exercise requires deployment of two DLLs in your applications?the wwScripting DLL that holds both the code execution and scripting classes as well as the remote loader DLL required to handle the AppDomain proxy Interface. I hope these classes and this discussion help you understand how to run dynamic code in .NET. I learned a lot about how .NET works under the covers and I hope this article and the provided helper classes are useful to you in extending your applications with dynamic code. I cannot live without this capability in my applications.

Get the Code from this Article



Share the Post:
Bold Evolution

Intel’s Bold Comeback

Intel, a leading figure in the semiconductor industry, has underperformed in the stock market over the past five years, with shares dropping by 4% as

Semiconductor market

Semiconductor Slump: Rebound on the Horizon

In recent years, the semiconductor sector has faced a slump due to decreasing PC and smartphone sales, especially in 2022 and 2023. Nonetheless, as 2024

Learn Web Security

An Easy Way to Learn Web Security

The Web Security Academy has recently introduced new educational courses designed to offer a comprehensible and straightforward journey through the intricate realm of web security.

Military Drones Revolution

Military Drones: New Mobile Command Centers

The Air Force Special Operations Command (AFSOC) is currently working on a pioneering project that aims to transform MQ-9 Reaper drones into mobile command centers

Tech Partnership

US and Vietnam: The Next Tech Leaders?

The US and Vietnam have entered into a series of multi-billion-dollar business deals, marking a significant leap forward in their cooperation in vital sectors like

Bold Evolution

Intel’s Bold Comeback

Intel, a leading figure in the semiconductor industry, has underperformed in the stock market over the past five years, with shares dropping by 4% as opposed to the 176% return

Semiconductor market

Semiconductor Slump: Rebound on the Horizon

In recent years, the semiconductor sector has faced a slump due to decreasing PC and smartphone sales, especially in 2022 and 2023. Nonetheless, as 2024 approaches, the industry seems to

Elevated Content Deals

Elevate Your Content Creation with Amazing Deals

The latest Tech Deals cater to creators of different levels and budgets, featuring a variety of computer accessories and tools designed specifically for content creation. Enhance your technological setup with

Learn Web Security

An Easy Way to Learn Web Security

The Web Security Academy has recently introduced new educational courses designed to offer a comprehensible and straightforward journey through the intricate realm of web security. These carefully designed learning courses

Military Drones Revolution

Military Drones: New Mobile Command Centers

The Air Force Special Operations Command (AFSOC) is currently working on a pioneering project that aims to transform MQ-9 Reaper drones into mobile command centers to better manage smaller unmanned

Tech Partnership

US and Vietnam: The Next Tech Leaders?

The US and Vietnam have entered into a series of multi-billion-dollar business deals, marking a significant leap forward in their cooperation in vital sectors like artificial intelligence (AI), semiconductors, and

Huge Savings

Score Massive Savings on Portable Gaming

This week in tech bargains, a well-known firm has considerably reduced the price of its portable gaming device, cutting costs by as much as 20 percent, which matches the lowest

Cloudfare Protection

Unbreakable: Cloudflare One Data Protection Suite

Recently, Cloudflare introduced its One Data Protection Suite, an extensive collection of sophisticated security tools designed to protect data in various environments, including web, private, and SaaS applications. The suite

Drone Revolution

Cool Drone Tech Unveiled at London Event

At the DSEI defense event in London, Israeli defense firms exhibited cutting-edge drone technology featuring vertical-takeoff-and-landing (VTOL) abilities while launching two innovative systems that have already been acquired by clients.

2D Semiconductor Revolution

Disrupting Electronics with 2D Semiconductors

The rapid development in electronic devices has created an increasing demand for advanced semiconductors. While silicon has traditionally been the go-to material for such applications, it suffers from certain limitations.

Cisco Growth

Cisco Cuts Jobs To Optimize Growth

Tech giant Cisco Systems Inc. recently unveiled plans to reduce its workforce in two Californian cities, with the goal of optimizing the company’s cost structure. The company has decided to

FAA Authorization

FAA Approves Drone Deliveries

In a significant development for the US drone industry, drone delivery company Zipline has gained Federal Aviation Administration (FAA) authorization, permitting them to operate drones beyond the visual line of

Mortgage Rate Challenges

Prop-Tech Firms Face Mortgage Rate Challenges

The surge in mortgage rates and a subsequent decrease in home buying have presented challenges for prop-tech firms like Divvy Homes, a rent-to-own start-up company. With a previous valuation of

Lighthouse Updates

Microsoft 365 Lighthouse: Powerful Updates

Microsoft has introduced a new update to Microsoft 365 Lighthouse, which includes support for alerts and notifications. This update is designed to give Managed Service Providers (MSPs) increased control and

Website Lock

Mysterious Website Blockage Sparks Concern

Recently, visitors of a well-known resource website encountered a message blocking their access, resulting in disappointment and frustration among its users. While the reason for this limitation remains uncertain, specialists

AI Tool

Unleashing AI Power with Microsoft 365 Copilot

Microsoft has recently unveiled the initial list of Australian clients who will benefit from Microsoft 365 (M365) Copilot through the exclusive invitation-only global Early Access Program. Prominent organizations participating in

Microsoft Egnyte Collaboration

Microsoft and Egnyte Collaboration

Microsoft has revealed a collaboration with Egnyte, a prominent platform for content cooperation and governance, with the goal of improving real-time collaboration features within Microsoft 365 and Microsoft Teams. This

Best Laptops

Top Programming Laptops of 2023

In 2023, many developers prioritize finding the best laptop for programming, whether at home, in the workplace, or on the go. A high-performing, portable, and user-friendly laptop could significantly influence

Renaissance Gaming Magic

AI Unleashes A Gaming Renaissance

In recent times, artificial intelligence has achieved remarkable progress, with resources like ChatGPT becoming more sophisticated and readily available. Pietro Schirano, the design lead at Brex, has explored the capabilities

New Apple Watch

The New Apple Watch Ultra 2 is Awesome

Apple is making waves in the smartwatch market with the introduction of the highly anticipated Apple Watch Ultra 2. This revolutionary device promises exceptional performance, robust design, and a myriad

Truth Unveiling

Unveiling Truths in Bowen’s SMR Controversy

Tony Wood from the Grattan Institute has voiced his concerns over Climate and Energy Minister Chris Bowen’s critique of the Coalition’s support for small modular nuclear reactors (SMRs). Wood points

Avoiding Crisis

Racing to Defy Looming Financial Crisis

Chinese property developer Country Garden is facing a liquidity challenge as it approaches a deadline to pay $15 million in interest associated with an offshore bond. With a 30-day grace

Open-Source Development

Open-Source Software Development is King

The increasingly digital world has led to the emergence of open-source software as a critical factor in modern software development, with more than 70% of the infrastructure, products, and services

Home Savings

Sensational Savings on Smart Home Security

For a limited time only, Amazon is offering massive discounts on a variety of intelligent home devices, including products from its Ring security range. Running until October 2 or while

Apple Unleashed

A Deep Dive into the iPhone 15 Pro Max

Apple recently unveiled its groundbreaking iPhone 15 Pro and iPhone 15 Pro Max models, featuring a revolutionary design, extraordinary display technology, and unrivaled performance. These new models are the first