DEV Community

Bruce Axtens
Bruce Axtens

Posted on • Updated on

Adding Assemblies on the fly in C# ClearScript projects

For those who've been following my antics with string reversals in JavaScript, you may recall me talking about Lychen, my wrapping of V8 JavaScript in a command-line tool accessing C# objects via ClearScript. It's a 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 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.

Question 22 of the ClearScript FAQtorial 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 hanging off the "CS" symbol. This makes possible calls such as,

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

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

Enter fullscreen mode Exit fullscreen mode

and

var data = CS.System.IO.File.ReadAllText(logfile).split(/\r\n/g);
Enter fullscreen mode Exit fullscreen mode

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

The FAQtorial's example gives

using Microsoft.ClearScript;

var typeCollection = new HostTypeCollection("mscorlib", "System", "System.Core");

engine.AddHostObject("clr", typeCollection);
Enter fullscreen mode Exit fullscreen mode

and up until recently I was doing the same, adding a few more assemblies like RestSharp. 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.

        private static void AddHostSymbols(ref V8ScriptEngine v8)
        {
            v8.AddHostObject("CSExtendedHost", new ExtendedHostFunctions());
            v8.AddHostObject("CSHost", new HostFunctions());
Enter fullscreen mode Exit fullscreen mode

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.

            var htc = new HostTypeCollection();
            foreach (var assembly in new string[] { "mscorlib", "System", "System.Core", "System.Data", "RestSharp", "WebDriver", "WebDriver.Support" })
            {
                htc.AddAssembly(assembly);
            }
Enter fullscreen mode Exit fullscreen mode

Next comes the reason for my joy.

I have a Settings dictionary (a Dictionary) 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.

            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);
                    }
                }
            }
Enter fullscreen mode Exit fullscreen mode

finally we hand the htc symbol off to the ClearScript engine.

            v8.AddHostObject("CS", htc);
        }
Enter fullscreen mode Exit fullscreen mode

What this means is

Lychen /REPL /ASSEMBLIES:"path to dll"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

Discussion (0)