Wednesday, November 24, 2010

Razor Template Engine

Razor Code can be parsed using Razor template engine. http://razorengine.codeplex.com/
Following sample demonstrate how to achieve that.  Both @function and @helper are working.

SIMPLE TEMPLATE
string template = "Hello @Model.Name! Welcome to Razor!";
            string result = Razor.Parse(template, new { Name = "World" });
            MessageBox.Show(result);

@FUNCTION
string template = "@functions{ public static string RenderDiscountedPrice(decimal price){    return \"Buy now for only 10 with $1.00 off!\";}}  @RenderDiscountedPrice(10);"; // WORKS
            string result = Razor.Parse(template,null);
            MessageBox.Show(result);

@HELPER
string template = "@helper RenderDiscountedPrice(decimal price){ \"Buy now for only 10 with $1.00 off!\";} Hello @RenderDiscountedPrice(10);"; // WORKS
            string result = Razor.Parse(template,null);
            MessageBox.Show(result);

MODEL
string template = "Users List :\n @foreach(var e in Model){\n  @e.Name  @e.Designation  }";       // WORKS
                var f = new FakeEmployeesRepository();
                string result = Razor.Parse(template, f.Employees);
                MessageBox.Show(result);


Where Employees Model is as follows;
public class Employee
       {
              public int EmployeeCode { get; set; }
              public string Name { get; set; }
              public string Designation { get; set; }
       }

public class FakeEmployeesRepository : IEmployeesRepository
       {
              // Hard Coded list of employees
              private static readonly IQueryable<Employee> _fakeEmployees = new List<Employee> {
        new Employee {EmployeeCode=1,  Name = "Imran", Designation="Senior Software Engineer"},
        new Employee {EmployeeCode=2,  Name = "Andrew", Designation="Graphic Designer"},
        new Employee {EmployeeCode=3,  Name = "Michael", Designation="Project Manager"},
        new Employee {EmployeeCode=4,  Name = "John", Designation="Database Administrator" },
        new Employee {EmployeeCode=5,  Name = "Robert", Designation="Project Director"}
        }.AsQueryable();

              public IQueryable<Employee> Employees
              {
                     get { return _fakeEmployees; }
              }
       }

Monday, November 22, 2010

MVC response caching

An MVC response can be cached on client side using [OutputCache].
e.g.
public class UserController : Controller
{
[OutputCache(Duration = 60, VaryByParam = "None")] // Duration in seconds
public ActionResult List()
{
try
{
UserCache objUsers = new UserCache();
return View(objUsers.GetUsersList());
}
catch (Exception ex)
{
throw ex;
}
}
}

Object Caching in ASP.NET

System.Web.Caching.Cache is used to cache objects on serverside.
e.g.
public IQueryable<User> GetUsersList()
{
UserModel objUsers = new UserModel();
if (HttpContext.Current.Cache["USERS"] == null)
HttpContext.Current.Cache.Add("USERS", objUsers.GeFakeUserList(), null, Cache.NoAbsoluteExpiration, System.TimeSpan.FromMinutes(20), CacheItemPriority.NotRemovable, null);
return (IQueryable<User>)HttpContext.Current.Cache["USERS"];
}
 

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;



        }

    }

}