Skip to content

Instantly share code, notes, and snippets.

@RexMorgan
Created September 9, 2011 07:30
Show Gist options
  • Save RexMorgan/1205677 to your computer and use it in GitHub Desktop.
Save RexMorgan/1205677 to your computer and use it in GitHub Desktop.
Razor Spike
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Web.Razor;
using Microsoft.CSharp;
namespace RazorTest
{
class Program
{
static void Main(string[] args)
{
// Change this to your path...
const string viewFile = @"C:\path\to\view.cshtml";
var viewTypeStr = string.Empty;
// I know this is retarded, I suck when it comes to streams...
var outputView = Path.Combine(Path.GetTempPath(),
string.Format("Temp_{0}.cshtml", Guid.NewGuid().ToString("N")));
using (var reader = new StreamReader(viewFile))
{
var line = reader.ReadLine();
if (line != null)
{
// Check to see if the first line is @model, if it is, grab the type, get the rest of the view and
// save it to a temp file that we can access later. This will be the rest of the view, minus the
// @model, which will freak out the compiler since it doesn't know wtf @model means.
if (line.Trim().StartsWith("@model "))
{
viewTypeStr = line.Trim().Split(new[] {' '})[1];
using (var writer = new StreamWriter(outputView, false))
{
var theRest = reader.ReadToEnd();
writer.Write(theRest);
writer.Flush();
}
}
}
}
// If we didn't find a @model, then bomb, we have to have one.
if(string.IsNullOrEmpty(viewTypeStr))
{
throw new InvalidOperationException("ModelType couldn't be found!");
}
// Get the type of the model
var modelType = Type.GetType(viewTypeStr);
// Create the generic base type for our razor view.
var baseType = typeof (BaseWriter<>).MakeGenericType(modelType);
var razorViewClass = string.Format("{0}RazorView", modelType.Name);
// Setup our razor engine
var host = new RazorEngineHost(new CSharpRazorCodeLanguage())
{
DefaultBaseClass = baseType.FullName,
DefaultNamespace = "RazorTest",
DefaultClassName = razorViewClass
};
host.NamespaceImports.Add("System");
host.NamespaceImports.Add("RazorTest");
var engine = new RazorTemplateEngine(host);
GeneratorResults razorResult;
// Read the temporary file we created and generate the code.
using(var reader = new StreamReader(outputView))
{
razorResult = engine.GenerateCode(reader);
}
// Compile our generated code
var codeProvider = new CSharpCodeProvider();
var outputAssemblyName = Path.Combine(Path.GetTempPath(),
string.Format("Temp_{0}.dll", Guid.NewGuid().ToString("N")));
var assemblies = new List<string>
{
new Uri(typeof (BaseWriter).Assembly.EscapedCodeBase).LocalPath
};
var compilerParameters = new CompilerParameters(assemblies.ToArray(), outputAssemblyName);
var results = codeProvider.CompileAssemblyFromDom(compilerParameters, razorResult.GeneratedCode);
// If we have errors, spit them out
if(results.Errors.HasErrors)
{
foreach(var error in results.Errors)
{
Console.WriteLine(error);
}
}
else
{
// Let's try to render the view, grab a new view model
var viewModel = new ViewModel
{
Name = "Fubu!",
TestList = new List<string> { "Test 1", "Test 2" }
};
var viewType = results.CompiledAssembly.GetType("RazorTest." + razorViewClass);
var view = Activator.CreateInstance(viewType);
// Not sure how to cast the object to our type, or to BaseWriter<T>, so I'm just calling it
// through reflection
var setModelMethod = viewType.GetMethod("SetModel");
setModelMethod.Invoke(view, new object[] { viewModel });
var executeMethod = viewType.GetMethod("Execute");
executeMethod.Invoke(view, null);
var rendered = (view as BaseWriter).Output;
// Should be full of win.
Console.Write(rendered);
}
Console.Read();
}
}
public class BaseWriter<T> : BaseWriter
{
protected T Model;
public void SetModel(T model)
{
Model = model;
}
}
public class BaseWriter
{
private readonly StringBuilder _sb;
public BaseWriter()
{
_sb = new StringBuilder();
}
public string Output
{
get { return _sb.ToString(); }
}
public void WriteLiteral(string literal)
{
_sb.Append(literal);
}
public void Write(object obj)
{
_sb.Append(obj);
}
public virtual void Execute()
{
}
}
public class ViewModel
{
public string Name { get; set; }
public List<string> TestList { get; set; }
}
}
@model RazorTest.ViewModel
Hello @Model.Name
@foreach (string s in Model.TestList) {
@:Item is equal to @s<br />
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment