Voice Networking Applications Prof. Kimmel Lecture #11 Copyright 2002 Zebadiah Kimmel, All Rights Reserved Introduction In this final lecture, we will talk about using C# and ASP .NET to create VoiceXML applications. This is a huge topic, so I'm just going to provide an overview here. What is ASP? ASP, Active Server Pages, is (was) a scripting environment made by Microsoft. It works in conjunction with Microsoft's web server (IIS). It is a scripting environment because the actual code is written in JavaScript or VBScript, then interpreted on-the-fly to produce HTML (or XML) pages. ASP is a crummy development environment, and leads to horrible coding practices, but it is easy to learn and use. What is ASP .NET? ASP .NET is very different than ASP, though you'd never guess it from the name; it is the use of Microsoft's .NET framework to produce HTML (or XML) pages. ASP .NET is vastly superior to ASP, and in my opinion substantially superior to Java Servlets/JSPs as well. Its major downside (a big one) is that ASP .NET is confined solely to Windows. ASP .NET allows you to use multiple languages—including C#, Visual Basic, and C++—to produce compiled programs that output HTML (or XML) pages. We are going to concentrate on C#, because it is very similar to Java. In fact, C# is basically Java with all the cruddy stuff taken out and a lot of good stuff added in. It is a great language….if only it were available for non-Microsoft platforms… Some notes on C# Like I just said, C# is basically the Java language with all the bad stuff taken out, and a lot of good stuff put in. If you have ever gotten annoyed with Java's idiosyncracies, then you will really like C#. For example, providing get/set access methods in Java is a real pain. If I declare a variable int x, then I also need to define int getX() and void setX(int x). On the other hand, C# combines variable declarations and accessors like this: public class MyClass { public int Year { get { return year; } set { year=value; } } private int year; } After defining MyYearClass, I can elsewhere in the C# world do something like this: MyClass mine = new MyClass(); mine.Year = 50; // in Java, this would be mine.setYear(50) System.Console.WriteLine(mine.Year); // in Java, this would be System.out.println(mine.getYear()) The C# notation is much easier to use, and more intuitive. C# includes features from C++, such as operator overloading, that are very useful. For example, you could define DateTime and Duration classes, then overload the + operator, to get behavior that looked like this: DateTime dt1 = new DateTime("January 1, 1970"); duration du = new Duration("31 days"); DateTime dt2 = dt1 + du; // dt2 is February 1, 1970 C# includes the amazingly useful foreach operator. For example, if parkingLot is an array of Cars, then you can do the following: foreach (Car c in parkingLot) { Console.WriteLine(c.ToString()); } C# gives you the ability to use something called an indexer to treat a collection as it were an array. For example, here is what using a C# Hashtable looks like: Hashtable hash = new Hashtable(); hash.Add("myKey", "myValue"); Console.WriteLine(hash["myKey"]); // prints out "myValue" Notice in the third line that hash is being treated as if it were an array. hash["myKey"] is just a convenient shorthand notation for the Java equivalent of hash.get("myKey"), but the convenience really adds up over time. C# includes classes for handling regular expressions. This is something that has been missing from Java for years. There is much, much more to C#. It is really a great language, and what Java should have become. The O'Reilly book on C# by Jesse Liberty is good if you want to learn more. The major downside, like I said before, is that if you want to use C#, then you'd better resign yourself to running your code on Windows only. Setting up ASP .NET on your computer While C# runs on a variety of Windows platforms, you will only be able to run ASP .NET on Win2K or WinXP-Pro. It won't work on Win95, Win98, WinNT, or WinXPHome. Thanks, Microsoft! Setting up ASP.NET is non-trivial. I started writing instructions on how to do it, and the instructions were taking up pages and pages and I was still nowhere near being done….so I'm going to ask you to get a book on this subject if you are really interested. You have to do the following: Install IIS (Internet Information Services) Configure IIS Install Microsoft Data Access Components (if you are going to use any databases) Install either the .NET Framework (which includes a whole buncha stuff including ASP.NET) or just ASP.NET on its own Chapter 1 of the book Beginning ASP.NET using C#, by Ullman et al, has detailed instructions on how to get ASP.NET working on your machine. Remember you can only run ASP.NET on Win2K or WinXP-Pro. A Simple ASP .NET Page This ASP.NET-generated VoiceXML page asks the user for a five-digit zip code, then submits that zip code to another ASP.NET page. (ASP.NET files end in .aspx.) Because of a bug in Nuance (described in Lecture 6), we can't have any whitespace between the <% Response.ContentType> tag and the <?xml> tag. <%@ Page language="c#"%> <% Response.ContentType="text/xml"; %><?xml version="1.0"?> <!DOCTYPE vxml PUBLIC '-//Nuance/DTD VoiceXML 1.0b//EN' 'http://voicexml.nuance.com/dtd/nuancevoicexml-1-2.dtd'> <vxml version="1.0"> <form> <field name="zipCode" type="digits" > <prompt count="1" bargein="true" Tell me a five digit zip </prompt> <prompt count="2" bargein="true" I didn't understand you. code. </prompt> <filled> <prompt> timeout="1s"> code. timeout="1s"> Please tell me a five digit zip OK. </prompt> <goto expr="'handle_zip_code.aspx?zipCode='+zipCode" /> </filled> </field> </form> </vxml> You can see that this ASP.NET page looks very similar to a JSP page. It begins with a page directive, declaring the page language to be C#. Then the content type of the response is set to XML. (In contrast to a JSP, the name of the Response object is capitalized.) The rest of the file is regular VoiceXML code. Just like a JSP, this page is compiled by .NET as needed. Unlike Java, the C# code is not compiled to byte-code, but rather to an intermediate language called Microsoft Intermediate Language (MSIL). From the point of view of the developer, though, ASP.NET's as-needed compilation looks and feels like JSP's as-needed compilation. A More Complicated ASP.NET Page The following example is more complicated (and contrived), to show you more aspects of making an ASP.NET page. This page could be called handle_zip_code.aspx, and could be the page to receive the zip code HTTP query from the previous example. <%@ Page language="c#" Debug="true" %> <%@ Import Namespace="System" %> <script language="c#" runat="server"> public int GetFirstDigit() { Application.Lock(); Application["zipCode"]=Request.QueryString["zipCode"]; Application.UnLock(); int FirstDigit = Convert.ToInt32(Application["zipCode"].ToString().Substring(0, 1)); return FirstDigit; } </script> <% Response.ContentType="text/xml"; %><?xml version="1.0"?> <!DOCTYPE vxml PUBLIC '-//Nuance/DTD VoiceXML 1.0b//EN' 'http://voicexml.nuance.com/dtd/nuancevoicexml-1-2.dtd'> <vxml version="1.0"> <form> <block> <prompt bargein="false"> The first digit of your zip code is <% int FirstDigit = GetFirstDigit(); Response.Write(FirstDigit); %> . </prompt> <% if ( FirstDigit > 5 ) Response.Write("<goto next=\"page_one.aspx\" />"); else Response.Write("<goto next=\"page_two.aspx\" />"); %> </block> </form> </vxml> There is a lot going on here. First, notice that the page directive sets Debug to be true. This means that when an error occurs, the web page response from .NET will detail the error. These .NET error reports are very useful and substantially more complete and helpful than Tomcat's error results. Next, you see an Import directive. As you would expect, this is just like Java's import keyword, with .NET's namespace equivalent to Java's package. Importing the System namespace gives us access to I/O libraries, such as string operations. There are many namespaces, corresponding to the various Java packages, although the .NET namespaces tend to be more complete and better organized than their Java equivalents—Microsoft had the opportunity to learn from Sun's mistakes. The <script> tag Next, we have a <script> statement. In .NET, the <script> tag is quite an interesting construct. If we just put in a <script> like this: <script> blah blah blah…. </script> …Then the <script> tag will be sent unchanged down to the client browser. This is how you send, for example, JavaScript code to a client web browser. But if we put in a <script> like this: <script language="c#" runat="server"> blah blah blah… </script> …Then the <script> tag is executed on the server, before any part of the page is sent down to the client browser. The client browser never sees the content of the <script> tag. This is a very clever construct, part of Microsoft's strategy of blending client and server together. It is clever because of this fact: simply by setting an attribute of an XML tag, we can control whether code is executed on a client or a server. This motif occurs throughout ASP.NET. Because a <script> tag that is run server-side is executed before the page gets sent to the client browser, it should contain only declarative code (such as function declarations). In the example above, we define a function called GetFirstDigit(), that extracts the first digit of a received zip code. I included some extra code in GetFirstDigit() to demonstrate a couple of things…. First, an "Application" objects exists that you can use to store information across the entire web application. It can be locked and unlocked for purposes of synchronization. In the example above, I extract the incoming zipCode parameter from the Request object, then place that parameter into the Application object so that the zipCode can be accessed anywhere in the web application. A Session object also exists, which does what you would expect (stores information during a single client-server session). Although analogues to ASP.NET's Application and Session exist in JSP, the .NET constructs are easier and more intuitive to use. Second, a "Convert" class exists that provides all sorts of conversion methods: for example, Convert.ToBoolean(), Convert.ToDateTime(), Convert.ToDecimal(), and so on. This is a lot easier than Java's solution to the conversion problem, which is to force the developer to wander through tons of classes trying to find conversion methods. Inline code blocks I mentioned that server-side <script> tags execute before the page is sent back to the browser. To execute code while the page is being sent downstream, you use an inline code block, which looks just like its JSP equivalent: <% blah blah blah… %> As you look through the example above, you can see that the remainder of the page looks very similar to a JSP page. The main difference is that the request and response Java objects have turned into capitalized Request and Response .NET objects. What exactly is an ASP.NET page? Recall that every JSP is actually really a Java Servlet; Tomcat converts each JSP into a Servlet as needed. Does ASP.NET do something similar with aspx files? The answer (as you would expect) is yes. Each aspx file that you write is compiled on an as-needed basis into a subclass of the System.Web.UI.Page class. Like Java's servlet class, the .NET Page class has lots of methods that your ASP.NET pages inherit and can therefore use at will. ASP.NET has the added advantage that its pages can inherit from each other (as discussed further below). I'm just going to mention one of the Page methods that you can use. The Page_Load method (which is empty by default) is executed when the page loads. You can override this method by declaring your own method of the same name in the <script> tag, like this: <script language="c#" runat="server"> void Page_Load() { blah blah blah… } </script> Whatever you put inside that method will then automatically execute when the page loads. This is useful for variable initialization. More sophisticated versions of Page_Load that receive event information, and lots of other Page methods besides, are also available. Another ASP.NET Example The Request and Response objects also provide useful methods. Here is a little example: <%@ Page language="c#" debug="true" %> <% Response.ContentType="text/html"; Response.AddHeader("Expires", "-1"); Response.AddHeader("Content-Expires", "-1"); Response.Redirect("http://www.mapquest.com/maps/map.adp?zipcode=" + Application["zipCode"] ); %> This redirects the client browser to a MapQuest page for the zipCode that is stored in the Application object. (Remember that this is a contrived example; in real life it probably wouldn't make much sense to store just a little zipCode in the Application object.) ASP.NET Server Controls Tomcat provides various XML tags (in the jsp: namespace) that you can embed in JSP pages. You can also build your own JSP tags. Similarly, ASP.NET provides various XML tags (in the asp: namespace) that you can embed in aspx pages, and you can build your own ASP.NET tags. Some of these ASP.NET tags are used to generate HTML controls, such as text boxes, drop-down lists, and buttons. Because the HTML for these tags is generated dynamically on the server-side, these tags are called HTML server controls. Here is an example: <%@ Page language="c#" debug="true" %> <% Response.ContentType="text/html"; %> <script runat="server" language="c#"> void Page_Load() { Message.Text = "Hello World"; } </script> <html> <body> <asp:label id="Message" runat="server" /> </body> </html> The <asp:label> tag is handled before anything is sent to the client browser (because its runat attribute is "server"). When ASP.NET sees this tag, it creates an internal object called Message (of class System.Web.UI.WebControls.Label). The Page_Load() method, which executes before anything is sent to the client browser, sets the textual content of the label to "Hello World". The end result is that "Hello World" appears in the browser window. Notice that Message.Text="Hello World" in C# is equivalent to Message.setText("Hello World") in Java, as per our previous discussion of get/set accessors. ASP.NET provides a variety of built-in server controls, including buttons, check boxes, tables, calendars, images, and advertisement rotators. Model-View-Controller in ASP.NET You can see even in these little examples that we are faced with the same problem we had with JSPs: the mixing of "pure code" (in this case, C#) with HTML/XML. Is there a way to separate program logic (programmatic statements, including conditional branches) from program presentation (the visual—or, in VoiceXML, audio—presentation of results to an end user)? The answer of course is yes, but ASP .NET handles this problem differently than does JSP. ASP.NET solves the problem by providing two mechanisms: So-called code-behind files, which are "pure C# code" files that are associated with aspx files. A wide variety of built-in server control tags, and the ability to build your own tags/controls (so-called custom controls). The model-view-controller equivalence between JSP and ASP.NET is therefore: view: JSP file aspx file controller: Java Servlet code-behind file model: JavaBean server/custom control (confusing name, unfortunately) A full exploration of these topics is infeasible here, but here is a short example. Code-Behind A code-behind file is similar to a Java Servlet. Here is a code-behind file called MyCodeBehind.cs. It defines an ASP.NET page that inherits from class Page. using System; using System.Web.UI; using System.Web.UI.WebControls; public class MyCodeBehind : Page { public TextBox user; public Label message; public void HandleButtonClick(object sender, EventArgs e) { message.Text = "Hello " + user.Text; } } Here is an aspx page that uses the code-behind file. Let's call this file MyCodeBehind.aspx. <%@ Page Inherits="MyCodeBehind" Src="MyCodeBehind.cs" %> <html> <body> <form action="MyCodeBehind.aspx" method="POST" runat="server"> <asp:TextBox id="user" runat="server" /> <asp:Label id="message" runat="server" /> <asp:Button text="Submit" OnClick="HandleButtonClick" runat="server" /> </form> </body> </html> This ASP.NET page displays a text entry box to enter a user name, and a Submit button. When the user presses the Submit button, the page re-appears, but with added text that says "Hello Bill" (or whatever the user name is). <asp:TextBox>, <asp:Label>, and <asp:Button> are all server control tags that are built into ASP.NET. By setting their runat attribute to "server", we make sure that those tags are processed on the server-side by ASP.NET, instead of being passed down as-is to a client browser (which probably wouldn't know what to do with them). The page directive lets ASP.NET know that this aspx file is inherited from our custom class (MyCodeBehind), and that it should watch out for any server controls that are defined in the custom class, as opposed to the aspx file. In this example, the textbox and label are defined in MyCodeBehind.cs. By marking the textbox and label using the id attribute, we alert ASP.NET to this fact. One nice thing about the way all of this works is that you can create ASP.NET pages that are subclasses of other pages, which makes control of program flow easier to manage. This is in distinction to JSP, where it is difficult/impossible (I admit that I don't know how to do it) to create JSP pages that are subclasses of Java Servlets. Also, ASP.NET automatically compiles a code-behind file for you, while Tomcat does not automatically compile a servlet for you. In the example above, you can clearly see that program logic is encapsulated in a C# .cs file (Control), and program presentation is encapsulated in an ASP.NET .aspx file (View). Again, this is analogous to the Java system of encapsulating program logic in a Java .java file, and program presentation in a JSP .jsp file. Encapsulating program data can be done via so-called custom controls. These controls, which are (as you would expect) C# classes, are much more wide-ranging than JavaBeans: for example, they can contain presentation information as well as pure data, and the way you use get/set accessors is much more sophisticated than in Java. Because they are somewhat complicated to describe, I'm not going to talk about them here. Summary This lecture was meant to give you an overview of what it is like to create VoiceXML (or HTML) documents in C# using Microsoft's ASP.NET. In general, ASP.NET provides a number of elegant and easy-to-use enhancements over Java Servlets/JSPs, and C# is (in my opinion) clearly a superior language to Java. The price you pay for using C# and ASP.NET, however, is that your code is under the control of one company and runs on only one platform. You have to decide yourself whether the trade-off is worth it.