Introduction to Dynamic Languages for ASP.NET
In the ASP.NET Futures release, the ASP.NET Dynamic Language Runtime (DLR) provides a layer for integrating dynamic languages with the common language runtime. This documentation covers:
- ASP.NET features supported by dynamic languages.
- How code is handled in dynamic-language pages.
The addition of support for a wide variety of dynamic languages gives ASP.NET users a new set of tools and new flexibility for building Web applications. The following walkthroughs in this section illustrate some of the functionality of dynamic languages in ASP.NET.
- Walkthrough: Using Dynamic Languages with ASP.NET
- Walkthrough: Using Shared Code with Dynamic Languages for ASP.NET
- Walkthrough: Debugging with Dynamic Languages for ASP.NET
- Walkthrough: Databinding with Dynamic Languages for ASP.NET
- Walkthrough: Creating a User Control with Dynamic Languages for ASP.NET
With Microsoft IronPython for ASP.NET, developers can use popular dynamic languages for the .NET Framework to create compelling Web applications. IronPython for ASP.NET are free extensions to ASP.NET that are targeted at:
- ASP.NET developers who want to enjoy the simplicity and flexibility of a dynamic language.
- Python developers looking to harness the power of ASP.NET and its rapid application development (RAD) environment.
Python’s clean object-oriented design, dynamic nature, richness of expression, ease of use, and concise syntax has won over many users in the last several years. IronPython is an implementation of the Python programming language running on the .NET Framework. It is well integrated with the rest of the .NET Framework and makes all .NET libraries easily available to Python programmers, while maintaining full compatibility with the Python language. To learn more about IronPython and to download the complete source code, please visit www.codeplex.com/ironpython.
Implementations of Ruby and Visual Basic are under development. Future releases will expose hosting interfaces and the API for integrating other languages.
In thisrelease, support for dynamic languages in ASP.NET was expanded from the earlier support for IronPython for ASP.NET. Support for dynamic languages in ASP.NET is built on the Dynamic Language Runtime (DLR), a new platform currently under development at Microsoft. The DLR simplifies hosting dynamic languages on the common language runtime.
In addition, dynamic languages work well with dynamic data controls for ASP.NET, a set of server controls that simplify the creation of data-driven Web applications. For more information, see Introduction to Dynamic Data Controls for ASP.NET and Walkthrough: Using Dynamic Data Controls with ASP.NET.
ASP.NET Features Supported by Dynamic Languages
If you already develop .NET pages, using dynamic language pages will not require a great deal of new learning. Most standard ASP.NET features are supported, including the following:
- Pages (.aspx files), user controls (.ascx files), and master pages (.master files).
- Server controls; that is, elements with the
runat="server"attribute. - Code that is included either inline or in separate code files. There are some differences from the standard ASP.NET compilation model, which are discussed later.
- Code snippets; that is,
<% ... %>,<%= ... %>, and<%# ... %>.
Application File
Dynamic languages for ASP.NET support a file similar to the Global.asax file. The file is named Global.ext, where ext is the language-specific extension. For example, the extension for IronPython files is .py, so the file name is Global.py.
Unlike the Global.asax file, which contains a directive (<%@ %> element) and a script block with a runat="server" attribute, the Global.ext file contains only code. For example, a simple global application file might contain code like the following:
IronPython
def Application_BeginRequest(app):
app.Response.Write('Hello application!') App_Script Directory
A dynamic language application contains an App_Script folder that is similar to the App_Code directory, except that it contains dynamic-language script files instead of static language code files. The purpose is the same, however; files in this directory contain classes that can be used by code anywhere in the application.
Generic HTTP Handlers
A dynamic language application can contain an HTTP handler that is the equivalent of an .ashx file in a standard ASP.NET application, although there are some differences. Dynamic language handlers are implemented as .aspx files. As with the Global.ext file, handlers in dynamic language applications contain only code. For example, a simple dynamic language handler named HelloWorldHandler.aspx might contain the following:
IronPython
<%@ Page Language="IronPython" %>
<Script runat="server">
Response.ContentType = "text/plain"
Response.Write("Hello World")
</Script> Features Not Supported
The dynamic languages for ASP.NET feature do not currently support an equivalent of Web services (.asmx files). The Web service architecture works only with standard .NET Framework types, which can be difficult to create with dynamic languages. In addition, Web service class methods must be decorated with special metadata attributes such as WebMethodAttribute, and many dynamic languages have no syntax for applying attributes.
In this release, there is very limited design time support, no intellisense support, and no support for writing ASP.NET MVC controllers using a dynamic language. These are all limitations we plan to address in future releases.
In the .NET Framework version 2.0, dynamic languages require full trust to emit Microsoft intermediate language (MSIL) for compilation at run time.
How Code Is Handled in Dynamic Language Pages
One difference between managed code and dynamic languages is the compilation model. Dynamic languages do not use CodeDOM, the core of the code-generation model for standard ASP.NET pages. The standard code-handling model requires inheriting from a base class and overriding members with specific type signatures. This can be problematic for dynamic languages.
In contrast to the standard compilation model, in which all user code in a page becomes part of a generated source file, each piece of dynamic language code in a page is treated as an individual entity. The implications of this are best seen by considering the various types of user code.
Code in <script> Elements
In standard ASP.NET pages, all user code in <script> elements that have the runat="server" attribute becomes part of the generated class. In contrast, in dynamic language pages, no new class is generated. Instead, ASP.NET directly instantiates the class specified by the inherits attribute. In this respect, the term "inherits" is inaccurate for dynamic language pages, because no inheritance occurs.
Instead of becoming part of a class, the code in a <script> element becomes a kind of companion code for the ScriptPage class. For example, the Page_Load method shown in the following example is not part of any class.
IronPython
<script runat="server">
def Page_Load(sender, args):
Response.Write("<p>Page_Load!</p>")
</script> Instead, members of the ScriptPage class, such as Response in this example, are injected by ASP.NET so that they are directly available to your code. The effect is that the members appear to be part of the class.
In dynamic language terminology, the code in the script block lives in a module. Usually there is one module associated with each HTTP request.
Code-behind Files
Everything that applies to code in <script> elements applies also to code in separate files. In the standard model, the code file contains a partial class declaration, which the compiler merges with the generated class. With dynamic languages, however, there is no class declaration in the code file. Instead, methods appear directly in the file, outside of any containing construct. Therefore, as with normal ASP.NET pages, the question of where to put your dynamic language code is purely a matter of personal preference
Code Snippets
Snippet expressions and statements (that is, <%= ... %> and <% ... %>) also execute in the context of the module created for the code belonging to the page. As a result, these snippets have access to methods and variables defined inline, in <script> elements, or in separate code files. For example, if you define a Multiply method in a <script> block, you can write <%= Multiply(6,7) %> in your page.
Code snippets also have access to the members of the Page class. For example, you can write <%= Title %> to display the title of the page.
Data-Binding Expressions
Data-binding expressions are a type of code snippet, but they are worth discussing separately because they work more naturally with dynamic languages.
In standard ASP.NET code, you might have a GridView control with a templated column containing the data-binding expression <%# Eval("City") %>. The Eval method is used to get the value the column named City for the current row in the data source.
With dynamic languages, the snippet is simply <%# City %>. City is a code expression in the dynamic language instead of a literal string that must be interpreted by using the Eval method. This means you can write expressions containing arbitrary code. For example, with IronPython you can write <%# City.lower() %> to display the value of the column in lower case.
This straightforward and powerful syntax is possible because dynamic languages support late-bound evaluation. The meaning of City is not known at parse time, but the dynamic language engine is able to bind it to the correct object at run time.
Dynamic Injector Mechanism
The compilation model for dynamic languages enables you to use simple syntax into which additional code is injected at run time. For example, you might have code that reads a value from the query string. The URL for the page might look like this:
http://someserver/somepage.aspx?MyValue=17
In a C# page, you can use the following code to obtain the value:
String myValue = Request.QueryString["MyValue"];
The dynamic injector mechanism allows you to write much simpler code in dynamic languages, as shown in the following examples:
IronPython
myVar = Request.MyValue
The support code for dynamic languages enables the registration of an object referred to as an injector. By registering as an injector, the object agrees to handle code that matches a certain pattern. For example, if the dynamic language engine is unable to resolve the expression SomeObj.SomeName, where SomeObj is an HttpRequest object and SomeName is not a real property of the HttpRequest object, the engine calls the injector that has been registered to handle that pattern. The injector handles the expression by calling SomeObj.QueryString["SomeString"]. The net effect is exactly the same, but the syntax is much cleaner.
The injector mechanism has many potential uses. For example, wherever you would write SomeControl.FindControl("SomeChildControl") in C#, you can write SomeControl.SomeChildControl in a dynamic language application. The mechanism is extensible and can be applied to any collection that is indexed by strings.
Compilation of Dynamic Code
Dynamic language engines parse code at run time, compile it on the fly, and execute the compiled code. They are not interpreters. Compiled code is reused wherever possible, for better performance.
Posted in: .NET Framework| Tags: HTTP Dynamic Language Support Introduction Dynamic Data IronPython Overview Generic HTTP Handler App_Script Dynamic CodeUsing Dynamic Languages with ASP.NET
This walkthrough provides you with an introduction to dynamic languages for ASP.NET. It guides you through creating a simple page in Microsoft Visual Studio, adding controls, and adding event handlers using dynamic languages.
Tasks illustrated in this walkthrough include:
- Adding controls to the default page.
- Adding event handlers in a separate code file, using dynamic languages.
- Adding a second page with event-handling code in the page.
Prerequisites
In order to complete this walkthrough, you will need:
- Microsoft Visual Studio 2008 or Visual Web Developer 2008 Express Edition.
- A copy of the website included in the ASP.NET Dynamic Language Support download. There is currently no project template, so it is necessary to copy the website in order to start with a blank ASP.NET Dynamic Language website.
This walkthrough assumes that you have a general understanding of working in Visual Web Developer. For an introduction, see Walkthrough: Creating a Basic Page in Visual Web Developer.
Creating a Web Site
In this part of the walkthrough, you will create a Web site with a dynamic language as the default language.
To create a Web site with a default ASP.NET Web page
- Copy the files from the ASP.NET Dynamic Language Support project into an empty directory.
- In Visual Studio (or Visual Web Developer), in the File menu, click Open Web Site. The Open Web Site dialog box is displayed.
- Select the directory in which you copied the files in step 1. Make sure that FileSystem is selected in the left panel of the dialog.
Note: You can use statically compiled languages in the same Web application by creating pages and components in different programming languages.
- Click Open. Visual Studio opens the folder as a website and displays the files in the Solution Explorer.
Adding Controls to the Default Page
In this part of the walkthrough, you will add server controls to the page.
To add controls to the page
- Switch to Design view.
- In the Toolbox, from the Standard group, drag three controls onto the page: a TextBox control, a Button control, and a Label control.
- Put the insertion point above the TextBox control, and then type Enter your name: to create a caption for the text box.
Programming the Button Control
For this walkthrough, you will write code that reads the name that the user enters into the text box and then displays the name in the Label control.
To add a button event handler
- Right-click the page and click View Code to show the separate code file. For example, if you are using IronPython, the file is Default.aspx.py.
The file contains a stub event handler for the Load event of the page.
Note: In IronPython, pass is a placeholder that does nothing.
- Replace the stub event handler with the following code to set the label text when the page is initialized:
IronPython
def Page_Load(sender, e): if not IsPostBack: Label1.Text = "...Your name here..."
- Add the following code to create an event handler for the button's
Clickevent:IronPython
def Button1_Click(sender, e): Label1.Text = Textbox1.Text
In this release, event handlers must be coded and bound manually. You cannot create them by double-clicking a control in Design view or by selecting an event in the Properties window.
Because dynamic languages do not have typed parameters and variables, you do not need to know the type of the event argument object.
Note: In this release, IntelliSense support for dynamically typed variables is limited. You can press CTRL+SPACE to get a list of code elements that are currently in scope.
- Switch to Default.aspx and go to Source view, and then bind the event handler by adding an
OnClickattribute to the Button control markup, as shown in the following example:<form id="form1" runat="server"> <div> Enter your name:<br /> <asp:TextBox ID="TextBox1" runat="server"> </asp:TextBox> <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click"/><br /> <br /> <asp:Label ID="Label1" runat="server" Text="Label"> </asp:Label> <br /> </div> </form>
- Press CTRL+F5 to run the page in the browser using the ASP.NET Development Server.
- Enter a name into the text box and click the button. The name you entered is displayed in the Label control. If the name does not appear, check the spelling of the event handler in the
OnClickattribute. - In the browser, optionally view the source of the page you are running.
- Close the browser.
Programming the Button Control
For this walkthrough, you will add dynamic language code in a script block.
To add a default button event handler
- Switch to Source view.
- Add the following code to initialize the label and to create an event handler for the button's Click event.
IronPython
<script runat="server"> def Page_Load(sender, e): if not IsPostBack: Label1.Text = "...Your name here..." def Button1_Click(sender, e): Label1.Text = Textbox1.Text </script>
- In the Button control, bind the event handler by adding the
OnClickattribute, as you did previously in this walkthrough. The following example shows the markup.<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click"/><br />
- Press CTRL+F5 to run the page in the browser using the ASP.NET Development Server.
Using Shared Code with Dynamic Languages for ASP.NET
Introduction
In this walkthrough, you will create a simple class with a dynamic language and then use it in an ASP.NET Web page.
Prerequisites
In order to complete this walkthrough, you will need:
- Microsoft Visual Studio 2008 or Visual Web Developer 2008 Express Edition.
- A copy of the website included in the ASP.NET Dynamic Language Support download. There is currently no project template, so it is necessary to copy the website in order to start with a blank ASP.NET Dynamic Language website.
This walkthrough assumes that you have a general understanding of working in Visual Studio. For an introduction, see Walkthrough: Creating a Basic Page in Visual Web Developer.
Using the Shared Class
The next step is to use the shared class in an ASP.NET Web page. You can use the Default.aspx page that was created when you created the Web site.
To use the shared class
- Open or switch to the Default.aspx page, and then switch to Design view.
Note If you do not have a Default.aspx page, you can use another page or add a new page to the Web site.
- From the Standard tab in the toolbox, drag a TextBox control, Label control, and Button control onto the page.
Note For this walkthrough, the layout of the page is not important.
- Right-click the page and click View Code, and then add import statements for the new module using the following code:
IronPython
from SampleModule import SampleClass
- Add an event handler for the Click event of the button, with the following code:
IronPython
def Button1_Click(sender, args): sc = SampleClass() sc.TestString = TextBox1.Text Label1.Text = sc.TestString
Note In this release, event handlers must be coded and bound manually. You cannot create them by double-clicking a control in Design view or by selecting an event in the Properties window.
- Switch to Source view, and then bind the event handler to the Click event using the following markup.
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click"/><br />
- Press CTRL+F5 to run the page.
- When the page appears in the browser, enter something in the text box, and then click the button.
The property of the sample class is set to the value of the TextBox control, and then displayed in the Label control.
Debugging with Dynamic Languages for ASP.NET, Part 2
Adding Controls and Code for Debugging
You can now add some controls to the page and then add code. The code will be simple, but enough to enable you to add breakpoints later.
To add controls and code for debugging
- Switch to Design view, and then from the Standard tab of the toolbox, drag the following controls onto the page and set their properties as indicated:
Control
PropertiesLabel
ID: CaptionLabel
Text: (empty)TextBox
ID: NumberTextBox
Text: (empty)Button
ID: SquareButton
Text: SquareLabel
ID: ResultLabel
Text: (empty)Note For this walkthrough, the layout of the page is not important.
- Right-click the page and click View Code.
In this release, event handlers must be coded and bound manually. You cannot create them by double-clicking a control in Design view or by selecting an event in the Properties window.
- Add an event handler for the button's Click event, with logic to call a function named
Squareto square the number entered by the user. The handler might look like the following example.Note The code example deliberately does not include error checking.
IronPython
def SquareButton_Click(sender, e): number = float(NumberTextBox.Text) result = Square(number) ResultLabel.Text = '%s squared is %8.2f' % \ (NumberTextBox.Text, result)
IronPython
def Square(number): return number + number
- Add code to set the text of the
CaptionLabelcontrol to Enter a number: if this is the first time the page is running, and thereafter to Enter another number:. The handler will look like the following.IronPython
def Page_Load(sender, e): postback = sender.IsPostBack if IsPostBack: CaptionLabel.Text = "Enter another number: " else: CaptionLabel.Text = "Enter a number: "
You can use the IsPostBack property by itself, as shown in the if statement, or qualified by
sender, as shown in the assignment statement. When it is used by itself, it is recognized as a property of the script page just as it is in C# and Visual Basic. In the assignment statement,sender.IsPostBackis used because later in the walkthrough it illustrates a limitation of debugging in the current release.Note In this case,
senderand the implicit page reference happen to be the same, because Page_Load handles a page event. - Save the page.
- Press CTRL+F5 to run the page without debugging.
- Enter a number (other than 2) and press the Square button.
Notice that the result is incorrect, because there is an intentional bug in the program.
- Close the browser.
Debugging the Page
In this part of the walkthrough, you will use the debugger to examine the page code line by line as it is running, add breakpoints to the code, and run the page in debug mode. You will start by setting breakpoints.
To set breakpoints
- In Source view, set a breakpoint on the following line:
IronPython
postback = sender.IsPostBack
Note When your code is in a separate file, you can toggle breakpoints by pressing F9, by right-clicking a line and choosing Breakpoint, or by clicking in the margin to left of the line. In this release, the only mechanism that works for code embedded in a Web page is clicking in the margin.
- Set another breakpoint on the following line of the
SquareButton_Clickhandler:IronPython
result = Square(number)
You are now ready to run the debugger.
To run the debugger
- In the Debug menu, click Start Debugging (or press F5) to run the page in debug mode.
Note The first time you debug, you will be prompted to modify the Web.config file to enable debugging. Debugging is disabled by default, for better performance.
Because the breakpoint is in the Page_Load event handler, the page has not finished processing yet. The browser is open, but the page is not yet displayed.
- Click the
postbackvariable and press SHIFT+F9 to display its value in a Quick Watch window. The value is null. -
Note In this release, the Locals window, the Watch and QuickWatch windows, and the Immediate window are limited to local variables in IronPython.
- Press F10 to execute the assignment statement, and check the value of
postback(IronPython only) to see that it is now false. - In the Debug menu, click Windows and then click Locals.
This opens the Locals window, which displays the values of variables and objects that are in scope at the current line being executed (IronPython only). The value of
postbackis false.Notice that
sender,IsPostBack,CaptionLabel, andSquareButtondo not appear in the Locals window. - In the Immediate window, use the question mark operator to examine the value of
postback(IronPython only).The Immediate window display will look like the following:
>? postback >false
- In the Debug menu, click Windows, click Watch, and then click Watch 1 (IronPython only).
Note: If you are using Visual Studio Express Edition, the debugger offers only a single Watch window.
- Right-click
postback, then click Add Watch to add thepostbackvariable to the watch.Note In the current release, you cannot right-click to add a watch if the code is in the page instead of in a separate file. Instead, you can enter the name of the variable in the first cell of the Name column in the Watch window.
- Press F10 several times to step through the if statement.
When the last line of the if statement has executed, the execution pointer pauses on the next function. The body of the Page_Load method is still in scope, as you can see from examining the Locals window.
- Press F5 to continue execution and display the page.
- Enter the value 7 into the text box and click the Square button.
The debugger is displayed again, with the breakpoint in the Page_Load event handler. Press F10 to execute the line. The Watch window shows that the value of
postbackis true. - Press F5 to continue.
The debugger processes the Page_Load event handler and enters the
SquareButton_Clickhandler, where it stops on the second breakpoint you set. - Press F11 to step into the
Squarefunction. - Continue stepping through the function until you return from it.
Notice that the value of
resultstill is not set (IronPython only). - Press F11 one more time, and note the incorrect value.
In the current release, you have to stop the debugger in order to correct the code.
- Press F5 to continue running the program.