Use razor in ASP. net mvc to customize the view engine framework (1)

Source: Internet
Author: User

ASP. NET mvc3 began to use razor as its view engine, replacing the original ASP. NET web form engine. I recently studied the implementation of razor in mvc3, and found a starting point to allow us to customize the view parsing Engine Based on razor syntax. It can be used in projects, such as mail template customization. Currently, it is only a demo version and is still being improved. Codeplex: http://codeof.codeplex.com/SourceControl/list/changesets where razorex

Let's take a look at the effect:

Suppose there is a template file action1.cshtml as follows:

 
@ {String STR = "Hello world! ";} <HTML>  

Compile C #CodeAs follows:

 
Public class testcontroller: templatecontroller {public actionresult Action1 () {templatedata ["title"] = "hello "; templatedata ["Students"] = new list <student> {New Student {id = 0, name = "Parker Zhou"}, new student {id = 1, name = "Sue Kuang" }}; return template (@ "D: \ project \ C # \ mymvc \ razorlab \ template \ test \ action1.cshtml ");}}

The final HTML is as follows:

<HTML>  

I designed a pattern similar to MVC that allows users to transmit data to the view through the Controller, parse the template using razor, and fill in the data.

 

The principle is actually very simple, similar to ASP. NET, after reading the TemplateResolved to class, Together with the static base classDynamic CompilationDLL,ReflectionThe code is output in HTML. In this process, reflection naturally does not need to be said. The key is how to parse and dynamically compile. In this article, I will introduce how to use Microsoft's source code for parsing. Because my code is not complete yet and still in the unit test phase, I will not make a mistake.

 

System. Web. Razor

In the source code of mvc3, the DLL system. Web. Razor should be noted here.

It uses the C # method to parse razor and generate correspondingCompilation Unit. The so-called compilation unit is a class codecompileunit in. net. This class saves the source code structure in codedom mode and can be used to generate code or dynamically compile code.

 

System. Web. Razor. razortemplateengine

The most important class in this project is system. Web. Razor. razortemplateengine, which can be directly used. WhereGeneratecodeMethod to parse the read TemplateCompilation Unit, It has multiple overloading. The following is the class generated after action1.cshtml is parsed. The class name, base class name, namespace, and referenced namespace can be customized:

Namespace templatepage. namespace {using razortemplateengine; using system. collections. generic; public class @__ templateinherit: @__ templatepage {# Line hidden public @__ templateinherit () {} public override void execute () {string STR = "Hello world! "; Writeliteral (" \ r \ n <HTML> \ r \ n 

the generated C # code is actually very easy to understand. The above C # code can be obtained from codecompileunit through csharpcodeprovider. (By The Way, csharpcodeprovider can only get code from codecompileunit, but it is not implemented in turn! I have not found a lot of information, and I am interested in implementing it with nrefactory.) As you can imagine, what we need to do is to implement a base class @ __templatepage to implement the templatedata, writeliteral, write, execute, etc. The following is my Implementation of the base class:

Using system; using system. collections. generic; using system. text; namespace razortemplateengine {// <summary> // This is the base class which the dynamic generated class will inherit from, // and the templatepagerazorhost define the class name, see templatepagerazorhost. defaultbaseclass // For more infomation // </Summary> public class _ templatepage {// <summary> // store the parse result /// </Summary> private stringbuilder resultbuilder = new stringbuilder (); /// <summary> // store the data passed from controller // </Summary> private dictionary <string, Object> templatedata = new dictionary <string, object> (); Public stringbuilder parseresult {get {return resultbuilder ;}} public dictionary <string, Object> templatedata {get {return templatedata ;}set {templatedata = value ;}} /// <summary> /// override by the dymanic generated class, the method name is defined in // generatedclasscontext. defaultexecutemethodname in system. web. razor // </Summary> Public Virtual void execute () {}/// <summary> // implement method in the dymanic generated class, the method name is defined in // generatedclasscontext. defaultwriteliteralmethodname in system. web. razor // </Summary> // <Param name = "literal"> </param> Public Virtual void writeliteral (string literal) {resultbuilder. append (literal);} // <summary> // implement method in the dymanic generated class, the method name is defined in // generatedclasscontext. defaultwritemethodname in system. web. razor // </Summary> // <Param name = "OBJ"> </param> Public Virtual void write (Object OBJ) {resultbuilder. append (obj. tostring ());}}}

 

System. Web. Razor. razorenginehost

ForRazortemplateengineThe generated class name, base class name, namespace, and referenced namespace all have default values, but we can change this default settingRazorenginehostThis class, many of the attributes in this class are virtual and can be inherited by override, these attributes can be changedRazortemplateengine. Therefore, what we need to do is to implement a self-inheritedRazorenginehostTo implement the above custom behavior. LastRazorenginehostOfPostprocessgeneratedcodeAfter the result is returned by the razortemplateengine. generatecode method, the method provides an opportunity to modify the codedom again, such as adding additional namespace references.

With the above understanding, we have to implement the following sample code:

Implement an inheritance of razorenginehost:

Public class testrazorenginhost: razorenginehost {public testrazorenginhost (): Base (new topology () {} public override string defaultbaseclass {get {return "pagebase";} set {base. defaultbaseclass = value ;}} public override string defaultclassname {get {return "pageinherit" ;}set {base. defaultclassname = value;} public override void postprocessgeneratedcode (system. codedom. codecompileunit, system. codedom. codenamespace generatednamespace, system. codedom. codetypedeclaration generatedclass, system. codedom. codemembermethod executemethod) {base. postprocessgeneratedcode (codecompileunit, generatednamespace, generatedclass, executemethod); generatednamespace. imports. add (New codenamespaceimport ("razorlab "));}}

the following test code is used to convert a razor-based template C: \ test. cshtml into C # code:

Testrazorenginhost host = new testrazorenginhost (); system. web. razor. razortemplateengine RTE = new system. web. razor. razortemplateengine (host); filestream FS = new filestream (@ "C: \ test. cshtml ", filemode. open); streamreader sr = new streamreader (FS); var codedomwrap = RTE. generatecode (SR); csharpcodeprovider provider = new csharpcodeprovider (); codegeneratoroptions Options = new codegeneratoroptions (); options. blanklinesbetweenmembers = false; options. indentstring = "\ t"; stringwriter Sw = new stringwriter (); string code = string. empty; try {provider. generatecodefromcompileunit (codedomwrap. generatedcode, SW, options); Sw. flush (); Code = Sw. getstringbuilder (). tostring (); debug. writeline (CODE);} catch {} finally {SW. close ();}

 

Currently, it is not time to carefully study the functions supported by the MVC framework, such as template nesting and strong type binding. I believe that if this idea is put into production, such a demand will be there. In a few days, I put the code on codeplex. interested colleagues can contact me. After all, the power of a person is limited. Next, I will introduce how to dynamically compile and enter the data in the template.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.