This article should be counted as the continuation of the Razor engine analysis, or the analysis is the previous article.
Why?
1. Asp. Net MVC is not very good either.
2. I have my own agile Web framework and still want to use the Razor engine.
3. dynamic compilation is very interesting. This is also a trend in the future. If someone is interested, I would like to write this content.
However, there are not many people who have these ideas. There are very few materials and discussions. Instead of linyuanyu, it is better to move back to the Internet. Do it yourself.
As described in the Razor engine analysis, the two main functions of Razor are template files and dynamic compilers. Can we simply ask for these two main features? Other Smart Search view files, although not spam, are also bound by the hands and feet. I can do it myself. What I lose is a rope, and what I get is the whole world.
It is easy to maintain the template function, especially the intelligent syntax support during design. When creating a project, select the MVC project, and delete the references related to other MVC, only Razor is left.
Compile? You cannot find this code, and it is drowned in a large number of auxiliary code. Fortunately, I have found it here. After the modification is simplified, you can use it directly without having to use a Web project.
First, use the Razor Domain Name Space.
[Csharp] view plaincopy
Using System. Web. Razor;
Using System. Web. Razor. Generator;
Using System. Web. Razor. Parser;
Step 1: dynamic compilation: parse the View File and generate the code. Yes, generate the code first. The Razor syntax can be said to be a private syntax. It must be written into standard code before compilation to generate the familiar C # class Type. Note that the template base class used in my code below is my own TeamplateBase, which will be implemented in a simple way later. Of course, the advantage is flexibility. You can also directly use the System. Web. MVC. WebViewPage of Asp. Net Mvc. However, I have not tried it. Other problems may occur and cannot be guaranteed.
[Csharp]
Public static Type Compile <T> (string template_path)
{
// Prepare a temporary class name to read the template file and the Razor code generator.
Var class_name = "c" + Guid. NewGuid (). ToString ("N ");
Var base_type = typeof (TemplateBase <>). MakeGenericType (typeof (T ));
Var template = File. ReadAllText (template_path );
Var host = new RazorEngineHost (new CSharpRazorCodeLanguage (), () => new HtmlMarkupParser ())
{
DefaultBaseClass = base_type.FullName,
DefaultClassName = class_name,
DefaultNamespace = "YourNameSpace. dynamic ",
GeneratedClassContext =
New GeneratedClassContext ("Execute", "Write", "WriteLiteral", "WriteTo ",
"WriteLiteralTo ",
"YourNameSpace. TemplateBase ")
};
Host. NamespaceImports. Add ("System ");
Host. NamespaceImports. Add ("YourNameSpaces ");
// Generate code
CodeCompileUnit code;
Using (var reader = new StringReader (template )){
Var generatedCode = new RazorTemplateEngine (host). GenerateCode (reader );
Code = generatedCode. GeneratedCode;
}
// Prepare compilation Parameters
Var @ params = new CompilerParameters
{
IncludeDebugInformation = false,
TempFiles = new TempFileCollection (AppDomain. CurrentDomain. DynamicDirectory ),
CompilerOptions = "/target: library/optimize ",
GenerateInMemory = false
};
Var assemblies = AppDomain. CurrentDomain
. GetAssemblies ()
. Where (a =>! A. IsDynamic)
. Select (a => a. Location)
. ToArray ();
@ Params. ReferencedAssemblies. AddRange (assemblies );
// Compile www.2cto.com
Var provider = new CSharpCodeProvider ();
Var compiled = provider. CompileAssemblyFromDom (@ params, code );
If (compiled. Errors. Count> 0 ){
Var compileErrors = string. Join ("\ r \ n", compiled. Errors. Cast <object> (). Select (o => o. ToString ()));
Throw new ApplicationException ("Failed to compile Razor:" + compileErrors );
}
// After compilation is successful, the dynamic Type after compilation is returned
Return compiled. CompiledAssembly. GetType ("Skight. Arch. Presentation. Web. Core. ViewEngins. Razor. dynamic." + class_name );
}
Step 2 is much simpler. Just like any static class, use reflection to create an instance, copy the Model object execution template, and the output result is, the data of the Model class is embedded automatically.
[Csharp]
Public static string Render <T> (T model, string template_path)
{
Var type = Compile <T> (template_path );
// Create a view instance
Var instance = (TemplateBase <T>) Activator. CreateInstance (type );
// Execution template (embed data into a file)
Instance. Model = model;
Instance. Execute ();
// Output the final result
Var result = instance. Result;
Return result;
}
Finally, let's take a look at the view template class, a base class and a generic base class. The latter is used for the previous type Model.
[Csharp]
Public abstract class TemplateBase
{
Public string Layout {get; set ;}
Public UrlHelper Url {get; set ;}
Public Func <string> RenderBody {get; set ;}
Public string Path {get; internal set ;}
Public string Result {get {return Writer. ToString ();}}
Protected TemplateBase ()
{
}
Public TextWriter Writer
{
Get
{
If (writer = null)
{Writer = new StringWriter ();
}
Return writer;
}
Set {
Writer = value;
}
}
Private TextWriter writer;
Public void Clear (){
Writer. Flush ();
}
Public virtual void Execute (){}
Public void Write (object @ object ){
If (@ object = null ){
Return;
}
Writer. Write (@ object );
}
Public void WriteLiteral (string @ string ){
If (@ string = null ){
Return;
}
Writer. Write (@ string );
}
Public static void WriteLiteralTo (TextWriter writer, string literal ){
If (literal = null ){
Return;
}
Writer. Write (literal );
}
Public static void WriteTo (TextWriter writer, object obj ){
If (obj = null ){
Return;
}
Writer. Write (obj );
}
}
Public abstract class TemplateBase <T>: TemplateBase
{
Public T Model {get; set ;}
}
From the excellent trip