Thursday, 12 September 2013

Coffee break with Roslyn

Over the last 3 years Microsoft has made some significant strides towards compiler as a service. Compiler as a service is a mechanism which enables the developer to create syntax (lexicon) and easily analyse, compile and/or execute the code to obtain a result. Until recently to write and execute C# code you would need to compile the outputs using a commandline compiler (such as csc.exe), csc.exe then outputs CIL which allows the runtime to JIT compile and execute on your architecture. Creation of modules and assemblies in CIL has always been easy due to the tooling in Visual Studio. It has always been very difficult to provide scripting and dynamic capabilities to actual applications. I am pleased to say that this is no longer the case thanks to the .NET compiler as a Service, Roslyn.

Rosyln has led to some really cool use-cases for the utilisation of C# (or VB) as a scripting language. One such project is ScriptCS. ScriptCS provides the ability to create and maintain full C# projects and run them in a "pure" JIT fashion. No longer do you have to call csc.exe to compile your C# applications, with Roslyn you can dynamically write C# and execute the output without the utilisation of native language tooling.

To demonstrate Roslyn I have created the following dynamic url generator. This console sample uses the Roslyn script engine to create a url template that is populated from a state object. As you can see it really is easy to implement and can provide powerful results.

namespace UrlExpressionLibrary
{
    using System;
    using Roslyn.Scripting.CSharp;

    public class Program
    {
        static void Main(string[] args)
        {
            var url = @"?Item1={VisitId}&Item2={TrustNumber}&Item3={VisitId.Substring(0,1)}&StartDate={System.Web.HttpUtility.UrlEncode(DateTime.Now.AddDays(-5).ToString())}&Item4={(1==0?""No"":""Yes"")}";
            var item = new PatientVisitEntity { VisitId = "V123456", TrustNumber = "P123456" };

            var engine = new ScriptEngine();
            var session = engine.CreateSession(item);
            session.AddReference(item.GetType().Assembly);
            session.AddReference("System.Web");
            session.ImportNamespace("System");
            session.ImportNamespace("System.Web");

            var expressions = System.Text.RegularExpressions.Regex.Matches(url, @"\{.*?\}");
            var outputUrl = url;

            foreach (var func in expressions)
            {
                var f = func.ToString();
                var realExp = f.Substring(1, f.Length - 2);
                var output = session.Execute(realExp).ToString();

                outputUrl = outputUrl.Replace(f, output);
            }

            Console.WriteLine(outputUrl);
            Console.ReadLine();
        }

        public class PatientVisitEntity
        {
            public string VisitId { get; set; }

            public string TrustNumber { get; set; }
        }
    }
}

Roslyn should not be confused with the previous DLR and CodeDom capabilities provided in the framework.  Roslyn is a pure compiler as a service and provides the c# compiler written completely in managed code.  It is not used solely for generating code and has no external dependency on external resources to compile code.  Roslyn is a full syntax analyser which will be the future of the .NET tooling environment.  I have no-idea where the DLR will go in the future, especially considering Microsoft's preference for type-safe programming.


So, start using Roslyn for all your dynamic use-cases, free the burden of previous scripting hacks.  The opportunities are endless.

No comments:

Post a Comment