Tuesday, November 2, 2010

Razor Parser without MVC

Razor Parser that parses a razor template, generate c# class on the fly, executes the assembly and returns output string.
Another excellent post can be found here. http://www.fidelitydesign.net/?p=208


using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.CodeDom;

using System.CodeDom.Compiler;

using System.Web.Razor;

using System.Web.Razor.Generator;

using System.Web.Razor.Parser;

using System.Web.Razor.Text;

using System.IO;

using System.Text.RegularExpressions;

using System.Diagnostics;

using Microsoft.VisualBasic;

using Microsoft.CSharp;

using RazorEngine.Templating;



namespace RazorLibrary

{

    public class Razor

    {

        public string GetRazorOutput(string template, T model)

        {



            Type modelType = typeof(T);  // Get type of model



            var codeDom = new CSharpCodeProvider(); // Will be used to generate source code on the fly and compile the assembly



            //Generate a razor class generator where class name is GeneratorClass with Namespace Razor.Dynamic

            CSharpRazorCodeGenerator generator = new CSharpRazorCodeGenerator("GeneratorClass", "Razor.Dynamic", null, new RazorEngineHost(new CSharpRazorCodeLanguage()));



            // Will be used to Parse Razor template

            var parser = new RazorParser(new CSharpCodeParser(), new HtmlMarkupParser()); // Razor Parser with C# and Html

            // Razor requires clear, execute, write and WriteLiteral methods which are defined in TemplateBase

            Type baseType = (modelType == null) ? typeof(TemplateBase) : typeof(TemplateBase<>).MakeGenericType(modelType);

            // Add base class to the generated class i.e. public class GeneratorClass : RazorLibrary.TemplateBase>

            generator.GeneratedClass.BaseTypes.Add(baseType);



            using (var reader = new StreamReader(new MemoryStream(Encoding.ASCII.GetBytes(template))))

            {

                parser.Parse(reader, generator); // reader:Input stream and generator:visitor Pattern

            }

            var builder = new StringBuilder();



            using (var writer = new StringWriter(builder))

            {

                // Generate source code into writer, using code generator

                codeDom.GenerateCodeFromCompileUnit(generator.GeneratedCode, writer, new CodeGeneratorOptions());

            }

            var @params = new CompilerParameters();

            foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())

            {

                @params.ReferencedAssemblies.Add(assembly.Location);

            }



            //The call to CompileAssemblyFromSource is where the assembly gets compiled. This method takes the parameters object and the source code, which is a string

            var result = codeDom.CompileAssemblyFromSource(@params, new[] { builder.ToString() });

            if (result.Errors != null && result.Errors.Count > 0)

                throw new Exception("Error in compilation."); // This can be made better by creating custom exceptions handler to traverse the errors collection

            // Create an instance of Razor.Dynamic.GeneratorClass

            ITemplate instance = (ITemplate)result.CompiledAssembly.CreateInstance("Razor.Dynamic.GeneratorClass");

            var Templates = new Dictionary<string, ITemplate>();

            if (instance is ITemplate)

                ((ITemplate)instance).Model = model;



            instance.Execute();

            return instance.Result;



        }

    }

}


No comments:

Post a Comment