Introduction: Why do we need a new compilation model?
Steps for compiling traditional ASP. NET pages
1. parsing.
Parses the. aspx file.
2. Construct the codedom tree
Build the codedom tree based on the parsing results (not dependent on the specific language)
3.CodeGenerate
Select the appropriate codedom provider based on the language defined in the @ page command,
Let this specific provider generate the derived class according to the codedom treeSource code.
4. Compile
The Code Compiled by codedom provider is DLL.
5. Execute
Generated by ASP. NET LoadingProgramSet, instantiate the code class, and use it to execute HTTP requests.
When codebehind is used, there will be a partial class involved in the operation of the above process.
The operating mechanism of. ascx and. Master is similar to this situation.
From the above operation process, we can find that if you need other languages to support Asp.net, this language requires
Provide the corresponding codedom provider and create a subclass of system. Web. UI. Page.
Ironpython is non-strongly typed, so this kind of work is of little significance.
Therefore, it is necessary to implement ironpython's support for Asp.net in a new way:
"No compilation required" Page
Asp.net 2.0 supports page models that do not need to be compiled. The declaration method is as follows:
<% @ Page compilationmode = "never" %>
If this attribute value is not specified, it is "Auto" by default ".
The difference between pages that do not need to be compiled and normal pages is that they are data-driven. Therefore
Better performance.
This page has the following restrictions because it is not compiled:
That is, it cannot contain user code. Only static html and server-side controls can be included.
The support for dynamic languages starts from here, removes these restrictions, and provides
Language support.
How does a page not need to be compiled work?
1. Parsing
2. Build the control builder tree
Taking <asp: textbox> as an example, the parsing result does not generate a small segment to define the textbox.
Control code, but create a corresponding control generator node.
3. Execute
ASP. NET requests the control generator tree for initialization, including the controls.
In this case, the subclass of the page class is not generated. The page class itself (or possibly
Is a custom base class, if the inherits attribute is specified ).
New ASP. NET Model Supporting Dynamic Language
This model is modified from the Asp.net model that never needs to be compiled.
First, because a model that does not need to be compiled will encounter errors when discovering user code, this behavior must be performed
Modification, which is implemented in system. Web. dll. When you have installed support for this dynamic language
A new version of system. Web. dll is used.
The change to ASP. NET is the pageparserfilter API. Here we provide external code for execution.
.
In the new model, we have registered the pageparserfilter class in Web. config to customize parsing.
And enable support for user code on pages that do not require compilation:
<Pages
Pageparserfiltertype = "Microsoft. Web. ironpython. UI. nocompilecodepageparserfilter"
.../>
Pageparserfilter provides the following functions:
1. If the page uses a Dynamic Language (currently only ironpython is supported), it needs to confirm whether the page inherits
From a base class.
2. If parser encounters a code snippet (<%... %>, <% =... %>, or <% #... %> ),
It replaces these code snippets with specific controls that contain the code. In this way
From Asp.net's point of view, there is indeed no code, but the code snippets become controls. This practice
This makes it possible to break through the limit that pages without compilation cannot contain code.
3. If parser finds the definition of an event processing function (such as onclick = "methodname"), similarly,
It is also replaced with a specific control.
4. If parser sends <SCRIPT runat = "server">, this element is processed as a page-level attribute.
In the next step, it will be passed to the custom base class in string mode.
Custom HTTP Module
This model implements a custom HTTP module. You must register the following in Web. config:
<Httpmodules>
<Add name = "pythonmodule"
Type = "Microsoft. Web. ironpython. dynamiclanguagehttpmodule"/>
</Httpmodules>
The role of registering this HTTP module is to be able to hook up to the application domain cycle as early as possible,
Register various components in the dynamic language environment. (Application domain is an area of the current process,
All the code in the current web program is executed ).
This HTTP module also provides similar support for dynamic languages in the global. asax file, which will be discussed later.
Custom Page Base Class
In the new model, all pages inherit from a base class called scriptpage. This class inherits from
System. Web. UI. Page. Similarly, we have the base class scriptusercontrol of the user control and the base class of the master page.
Scriptmaster
Page Features supported by the new model
Most of the original features are basically supported, but they work in different ways.
Application file
The new model supports files similar to global. asax, but its name is global. Ext (EXT is language-specific,
For example, ironpython is global. py)
Another difference is that the file can only contain code and does not need to contain <% @ %> or runat = "server"
Such a statement.
For example, global. py can be written as follows:
Def application_beginrequest (APP ):
App. response. Write ("Hello application! ");
App_script directory
This directory is similar to the app_code directory of Asp.net 2.0. It can contain dynamic language files. Here
Can be called by the entire application.
Generic HTTP handlers
The Asp.net program in the dynamic language can contain an HTTP file similar to the. ashx file in the traditional Asp.net.
Handler, but like global. asax, it is slightly different.
Specifically, handler can only contain code without declarative statements.
The naming method is as follows:
Web_name.ext
For example, a handler of ironpython can be named as follows:
Web_myhellohandler.py
Note that the prefix "Web _" is specified to identify an HTTP handler.
The handler of the Dynamic Language must contain a processrequest method, which is similar to
Ihttphandler. processrequest method. Example:
Def processrequest (context ):
Context. response. Write ("Hello web handler! ")
Not supported: Web Services
The main reason is that the Web service architecture can only use the basic. NET Framework type, while Dynamic Language
It is not easy to create them. In addition, the web services method must be added with a tag similar to [webmethod,
There is no similar syntax in dynamic languages.
In the new model, how is the code processed?
Each segment of user code is processed as an independent entity. The following is a detailed analysis of different types
How the user code is processed:
<SCRIPT runat = "server"> code in the element:
In the traditional model, the code is generated as part of the page class. The new model does not produce new classes,
Asp.net directly instantiate the specified class (scriptpage) in the inherits attribute ). The meaning of "inherits"
It is no longer accurate.
<SCRIPT> the code in the element changes to some additional code of the scriptpage class, which can be roughly understood as similar
Partial class mechanism.
The following is an example:
<SCRIPT runat = "server">
Def page_load ():
Response. Write ("<p> page_load! </P> ")
</SCRIPT>
This Code does not become part of any class. The actual situation is that the page class members will be injected by Asp.net.
(Injected) to the environment so that they can be called here. (For example, using a respnose object)
From a practical point of view, you can regard this method as part of the page class, although it is not actually.
In ironpython terminology, the code in a code block exists in a module. Usually a page class,
Either a user control or a master page corresponds to a module. (Note that each page corresponds to a module,
Instead of generating one for each HTTP request ).
Let's look at another example:
<SCRIPT runat = "server">
Somevar = 5
</SCRIPT>
Note that this variable is module-level, and the above mentioned module corresponds to each page, so this variable is also.
This is similar to the static variable semantics of Asp.net.
Code-behind files)
The new model also supports the back-end code method, but it is different from the traditional model.
In the new model, there is no class definition in the backend code, and the method is directly defined in the file. This is the same as
<SCRIPT runat = "server"> the code in the block is no different.
The name of the backend code file can be named like mypage. aspx. py.
Code snippet (code snippets)
The code snippet expression (<% =... %>) is executed in the module that is accompanied by the page statement (<%... %>.
Because of this principle, the code snippets can freely access any method defined in the module.
For example: <% = multiply (6, 7) %>, where multiply is defined in the backend code. Code snippets can even
Access the members of the page class. For example:
<% = Title %> the title of the current page category is displayed.
Data Binding expression
Although the data binding expression is also a code snippet, it is necessary to explain it separately. Because in ironpython
Data Binding is more interesting than Asp.net binding.
For example, in the template column of the gridview, you can use the <% # eval ("city") %> syntax to bind the City field.
. This is common, but it is awkward to call it through the eval syntax ~
In the new model, we only need to do this: <% # city %> is it very exciting?
The city here is actually a real code snippet of the Dynamic Language, rather than a string of the original eval method.
Type parameter. Therefore, there is a lot of space to play here. For example, you can:
<% # City. Lower () %>.
This syntax is supported by the dynamic language's late-bound evaluation feature.
Although the meaning of city is unknown in the parse stage, the dynamic language engine can bind it to the correct
.
Dynamic injector Mechanism)
Another advantage of dynamic languages compared to static compiling languages is the injection mechanism. Example:
Assume that you need to obtain a value from the query string on the following page:
Http: // someserver/somepage. aspx? Myvalue = 17
In C #, You need:
String myvalue = request. querystring ["myvalue"];
In dynamic languages, you can:
Myvar = request. myvalue;
Why can I write it like this? In the new model, we registered a special object called injector ).
This injector acts as if it sends the following command to the Dynamic Language engine: "If an expression someobj. somename is found,
Someobj is an httprequest object, and somename is not an attribute of httprequest,
Let me handle it, rather than throw a failure ".
This injector processes the expression by calling someobj. querystring ["somename"].
The same injector mechanism is also implemented in other scenarios. For example,
C #: somecontrol. findcontrol ("somechildcontrol ")
Ironpython: somecontrol. somechildcontrol.
The injector mechanism is scalable. Therefore, if you have a custom set indexed by strings,
You can implement a custom Injector to simplify the syntax.
Although it is not a revolutionary change, the features of the injector mentioned above and the simplified binding expression will make
It is easier to develop web programs.
Dynamic code compilation
As mentioned above, the new model uses a non-compiled page model, which may cause misunderstanding and make you think the page is an explanation.
This is not the case.
The specific explanation is: The term "no-compile" actually refers to static compilation in codedom mode.
In the new model, the dynamic language code is locally compiled by the dynamic language engine (being compiled on-the-fly ).
Benefits of the new model
Faster page Initialization
When a traditional page accesses a page for the first time, there will be a complicated codedom compilation process, and
Loading an independent process (such as csc.exe) for compilation is very slow.
For non-compiled pages, the most expensive step is parsing, so the page will be executed faster.
Better performance
The traditional model will compile the page into an assembly and load it into the application domain for execution. However, once the Assembly
If it is loaded, it cannot be detached. Therefore, if you have a very large site with many pages, more and more
Program assembly is loaded, and may even cause insufficient memory. (Out of memory)
Asp.net uses a series of methods to relieve this burden. First, it can compile multiple pages to one
Assembly to reduce the number of loaded assembly. This is indeed helpful, but it brings a lot of complexity.
This is just a delay in solving the problem. Under some circumstances, Asp.net will uninstall the entire application domain and
Restart one to run the application. But this is a very heavyweight operation, because many Assembly requirements are short
Time is reloaded.
On the contrary, the new model does not have this problem because it does not generate an assembly at all. Of course
There are some additional costs for page processing, but the Garbage Collector will recycle the memory occupied.
Although dynamic code is usually compiled into Il, this compilation is very different from static compilation. Dynamic language compilation
Il uses a common language runtime feature called Lightweight code generation.
(Lightweight code generation, LCG). This feature can make the memory occupied during code compilation no longer
Recycled during use-you do not need to restart the entire application domain.
Look at numbers
What is the performance benefit of the new model? The difference between the new model and the traditional model is very obvious.
In the static compilation model, a website with 10,000 Asp.net pages will pose a huge burden on the server.
(Depends on the hardware configuration ). In comparison, you can run more than 1 million dynamic pages on the new model.
The server does not feel a lot of pressure!
It should be noted that the Asp.net static compilation model works well for most projects. Only for extremely large projects
You will feel this performance restriction.
Reduced Complexity (CED complexity)
As mentioned above, in order to improve the performance of static compilation, Asp.net compiles pages in batches. However, to achieve this
Very skillful, and this optimization has greatly improved the complexity of the entire compilation system.
This complexity is briefly described. In common cases, you have many pages and many user controls.
In order to compile them in batches, we must first figure out their dependency tree. (For example, page a references user control B ),
Because the dependent file must be compiled before the current compiled page. And we need to process different languages
The page for writing. Consider what if an old assembly is no longer valid but cannot be uninstalled?
What if two pages use the same class name? Batch compilation will cause compilation errors. Similar problems
A lot, but you probably can understand this complexity.
As mentioned above, it does not complain about how difficult it is to implement the static compilation model, but to compare it with the new model.
Because in short, only the page itself is processed, and you do not need to consider whether the old assembly is already in the current application domain
Loading can significantly reduce the complexity. We hope this will bring more stable products and fewer
Bugs. In short, the simplicity is always better!
Runtime Performance
Generally, static compiling languages such as C # are faster than dynamic languages such as ironpython. Because of Dynamic Language
It is executed by binding later. In Dynamic Language, object. perperty is the expression of property.
The meaning is not parsed during compilation, but at runtime. Parsing expressions require some form of search, which is essentially
It is slower than static compilation. Static compilation knows this value during compilation.
However, our question is not whether the dynamic language can run as fast as the static language, but the Asp.net page
Can Dynamic Language Writing achieve better performance. Tested Asp.net page written by ironpython
The running performance is quite good. The reason is that the execution of user code (static or dynamic) is only HTTP
A small part of request processing. Even if more time is spent on user code, the overall request
The difference in time is also small to negligible.
Of course, you can easily write a page to execute complex operations, which shows that this is wrong. But in fact
Most website pages do not have high CPU requirements for code execution. Most of the actual web page logic
It takes some time to process the input, set the value to the properties of the control, and query the database.
In short, for most web applications you need to build, using dynamic languages does not bring much
Negative impact.
Conclusion
In this document, we compared the differences between the existing static compilation model and the new model. The purpose is not to persuade
Existing C # web developers use ironpython instead. In fact, the purpose of this document is to explain the two
The differences between models allow you to stay focused on the work we are engaged in. In addition, there is still a lot of work to continue,
We hope to provide a revised version of this document in the future.