Created
September 9, 2011 07:30
-
-
Save RexMorgan/1205677 to your computer and use it in GitHub Desktop.
Razor Spike
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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