Adding Assemblies on the fly in C# ClearScript projects
Tags: clearscript, javascript, csharp, dotnet
Published: 2019-07-27 14:23:53

---
title: Adding Assemblies on the fly in C# ClearScript projects
published: true
description: C#, ClearScript, Lychen
tags: clearscript, javascript, csharp, dotnet
---

For those who've been following my antics with string reversals in JavaScript, you may recall me talking about [Lychen](https://github.com/axtens/Lychen), my wrapping of [V8](https://v8.dev/) JavaScript in a command-line tool accessing C# objects via [ClearScript](https://github.com/microsoft/ClearScript).  It's a [Claytons](https://en.wikipedia.org/wiki/Claytons) Node.js -- the Node you have when you're not having Node. 

I heartily recommend ClearScript as a way of adding JavaScript (or [VBScript](https://en.wikipedia.org/wiki/VBScript) for that matter) to your application. We also use it where I work, though we're still using the other JavaScript engine, [Microsoft's JScript](https://en.wikipedia.org/wiki/JScript). 

Question 22 of the [ClearScript FAQtorial](https://microsoft.github.io/ClearScript/Tutorial/FAQtorial.html) asks, "Can I expose many host types in one step?" and I've been using the technique discussed there to expose a variety of assemblies into Lychen as a large [PropertyBag](https://docs.microsoft.com/en-us/dotnet/api/microsoft.web.management.server.propertybag?view=iis-dotnet) hanging off the "CS" symbol. This makes possible calls such as,

```javascript
var mail = CS.System.Net.Mail;
var message = new mail.MailMessage();

message.From = new mail.MailAddress(
    CSScriptINI.IniReadValue("Settings", "ReplyToEmail", ""),
    CSScriptINI.IniReadValue("Settings", "ReplyToName", ""));

```

and 

```javascript
var data = CS.System.IO.File.ReadAllText(logfile).split(/\r\n/g);
```

Just of late I've been trying to work out how to add more. 

The FAQtorial's example gives

```javascript
using Microsoft.ClearScript;
…
var typeCollection = new HostTypeCollection("mscorlib", "System", "System.Core");

engine.AddHostObject("clr", typeCollection);
```

and up until recently I was doing the same, adding a few more assemblies like [RestSharp](http://restsharp.org/). For a while I believed that I needed to add these assemblies to my project. I thought this largely because the only way I could have the DLLs appear in my \bin\Debug folder was to have their project in mine.

It took me a while too to figure out that the project name wasn't what needed to be in the list of assembly names. Rather it was the name of the DLL (minus the ".dll" extension).

Just last week I figured out how to add *any* .NET DLL to a Lychen run. The code is below.

`AddHostSymbols` starts with creating symbols `CSExtendedHost` and `CSHost` to hook to the matching ClearScript objects, `ExtendedHostFunctions` and `HostFunctions`. 

```c#
        private static void AddHostSymbols(ref V8ScriptEngine v8)
        {
            v8.AddHostObject("CSExtendedHost", new ExtendedHostFunctions());
            v8.AddHostObject("CSHost", new HostFunctions());
```
Next it instantiates a HostTypeCollection object and adds a pile of assembly names to it. It's assumed that these are readily available either from the GAC or from local to the EXE.
```c#
            var htc = new HostTypeCollection();
            foreach (var assembly in new string[] { "mscorlib", "System", "System.Core", "System.Data", "RestSharp", "WebDriver", "WebDriver.Support" })
            {
                htc.AddAssembly(assembly);
            }
```
Next comes the reason for my joy. 

I have a Settings dictionary (a Dictionary<string,object>) which contains the command line parameters. I check for the presence of `/ASSEMBLIES`. If the symbol is there, I assume that its argument is a comma-separated list of paths to assemblies. I pass each path to `System.Reflection.Assembly.LoadFrom()` and then pass the resulting Assembly to the htc object. (`.AddAssembly()` will accept a string or an Assembly object.) There's a bit of error checking to catch FileNotFound errors.

```c#
            if (Settings.ContainsKey("/ASSEMBLIES"))
            {
                var assemblies = Settings["/ASSEMBLIES"].ToString().Split(',');
                foreach (var assembly  in assemblies)
                {
                    System.Reflection.Assembly assem;
                    try
                    {
                        assem = System.Reflection.Assembly.LoadFrom(assembly);
                        htc.AddAssembly(assem);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.Message);
                    }
                }
            }
```
finally we hand the htc symbol off to the ClearScript engine.
```c#
            v8.AddHostObject("CS", htc);
        }
```
What this means is 
```
Lychen /REPL /ASSEMBLIES:"path to dll"
```
Which could look like this:
```
>LYCHEN /REPL /ASSEMBLIES:"c:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.VisualBasic.dll"
Lychen>CS.Microsoft.VisualBasic
Microsoft.ClearScript.PropertyBag
Lychen>CS.Microsoft.VisualBasic.DateAndTime
HostType:DateAndTime
Lychen>CS.Microsoft.VisualBasic.DateAndTime.DateString
07-27-2019
```

All sorts of interesting DevOps scripting possibilities there, ہے نہ ؟