From the August 2002 issue of MSDN Magazine

MSDN Magazine

Code-behind in ASPX Files
George Shepherd The ASP Column Archive
Download the code for this article:  ASPColumn0208.exe (121 KB)
I

n the mid 1990s, it looked like COM was going to solve all the problems associated with component software (that is, the distribution and integration of software). However, cracks began to appear in the foundation around 1997 or so. For example, COM didn't solve the versioning problem as well as was anticipated. In addition, there were other issues; chiefly, a lack of fidelity between the data types available in code and the type information included with COM type information. While one of the main thrusts of the Microsoft® .NET platform is to make Web programming more approachable, the platform also aims to solve the problems of COM. The result is the common language runtime (CLR).
      The CLR is an amazing thing. It represents the best features of component software brought together under one roof. These include garbage collection, support for interfaces, and true binary compatibility (no more weird issues with SafeArrays, variants, or IDispatch, and integrated type information). This list isn't exhaustive, but it should give you a good idea of what the CLR is all about.
      If you've spent some time with classic ASP, you're undoubtedly familiar with some of its issues—most notably the problems associated with versioning and the limitations imposed by IDispatch. For example, you can use only VARIANT types if you want to support scripts in your ASP page. Another issue is that code and presentation are often mingled. Many classic ASP pages end up being a smear of HTML and script blocks. The ASP.NET solution to these problems is the code-behind model enabled by the CLR.
      The code-behind model lets you write your presentation code in one source code file, usually an ASPX file, and your execution logic in another module (often a C# or Visual Basic® .NET source code file or an assembly). If you develop in Visual Basic already, you probably want to stick with the Visual Basic syntax. If you're in the mood to try something new, C# provides a clean and rich paradigm of developing code-behind modules. While C# is a comfortable syntax for seasoned C++ developers, it does have its own format and some differences from C++ that require getting used to. If you're experienced in using C++ and you don't want to learn a new language syntax right away, there is a third option: using C++ to write your code-behind pages. In this month's column I'm going to take a look at what it takes to write ASP code-behind pages using Managed C++.

Managed C++

      Microsoft is an industry leader in backward-compatibility software. They've learned that the most effective way to get as many people as possible to use software is to provide smooth and painless ways of bridging the gap between current and new versions. There is a ton of C++ code out there and a huge number of developers who are really comfortable using it. Software has something of a half-life; it doesn't disappear overnight. In fact, it's really hard to discard software outright. .NET would not be very widely adopted if it required developers and companies to abandon all the work they've done over the years. To that end, Microsoft includes new extensions to C++ to generate code that runs under the CLR.
      If you're a seasoned C++ developer, you're used to making sure there's an invocation delete for every new statement. You're accustomed to writing IDL code that is separate from your C++ source code. In addition, you're probably annoyed by all the bugs that come from chasing down the wrong pointer or forgetting to delete a piece of memory. By using the new Managed C++ extensions from Visual C++® .NET, you get the compiler to emit an assembly that runs under the CLR. Any classes marked using the extensions become garbage collected, just like other managed code. You can allocate instances and never have to worry about deleting them. The runtime will do that for you. In addition, the C++ compiler will automatically generate type information/metadata for your assembly, so you don't need to write separate IDL code. Finally, running under the CLR gets rid of bizarre crashes that come from accessing invalid pointers (under the CLR, you get predictable exceptions).
      It turns out that writing a Managed C++ code-behind isn't all that hard to do. It's just that there are scant good examples using C++ out there. So here's the process of writing an ASP.NET code-behind page using Managed C++.

The ASPX Page

      I'll start off with the ASPX page. This one will display a list of the best features of ASP.NET. As a simple example, the page presentation will show the list of features, ask the user's name, then ask the user to submit their favorite feature. I'll keep all the presentation elements within the ASPX code and all the logical execution elements within the code-behind page (see Figure 1).
      The Page directive at the top of the ASPX page in Figure 1 indicates that page should be based upon a class named ManagedCWebForm.ManagedCWebPage. ASP.NET will expect to find this class in one of the assemblies along the probing path. In this case, I'll write the ManagedCWebForm.ManagedCWebPage class using Managed C++ and place the assembly in the \bin directory of the Internet Information Services (IIS) virtual directory hosting the page. Then the ASPX page declares a couple of server-side controls: a push button, label, textbox, and dropdown list. Notice they are all marked "runat= server." Also notice there is a line within the ASPX code that calls the function WriteArray. The WriteArray method will be implemented within the code-behind page. Finally, notice the push button is wired up to an event handler named Sub-mitEntry. Figure 2 shows the page as it would appear in real life. Now let's add some beef to it by developing a code-behind module.

Figure 2 Code-behind Page
Figure 2 Code-behind Page

      The easiest way to create a Managed C++ assembly is to use the wizard that comes with Visual Studio® .NET. Select New Project and under the C++ Project templates, pick Managed C++ Class Library. The Visual Studio AppWizard pumps out some source code files. Figure 3 lists the files created by the AppWizard.
      The Managed C++ library starts out barren. Compiling and linking the code generates an empty assembly. You need to add the code-behind class. Just as you do when writing a code-behind class in C# or Visual Basic .NET, you need to base the code-behind class on the System.Web.UI.Page class. To do that you need to make sure the managed assembly refers to the correct system modules and namespaces.
      When building assemblies using Visual Basic .NET or C# within Visual Studio .NET, the project needs to point to the correct assemblies. It's easy to do this using the Visual Studio .NET Project | References menu option. When using C++, refer to external assemblies through the #using C++ preprocessor directive. In addition, for convenience's sake, it's often useful to specify which namespaces to use so you don't have to keep scoping each declaration. The following code shows the directives for referring to the System and the Web assemblies, as well as defining the default namespaces.

#using <System.Dll>
#using <System.Web.dll>
 
using namespace System;
using namespace System::Web;
using namespace System::Web::UI;
using namespace 
  System::Web::UI::WebControls;
using namespace System::Collections;
using namespace System::ComponentModel;

Note that the syntax for declaring which namespaces to use follows the standard C++ scoping syntax. The heart of the code-behind module is a class that derives from System.Web.UI.Page. I'll take a look at that now.

The Page Class

      Figure 4 shows the C++ code describing the code-behind page. While the code in Figure 4 looks mostly like regular C++, it differs in several significant ways. First, notice that the ManagedCWebPage class has a public modifier preceding it. The CLR enforces visibility at the module level—not just at the class member level as in basic C++. Putting the public keyword before the ManagedCWebPage class declaration causes the whole class to be visible outside the assembly. This is important because the ASPX page will need to be able to access the ManagedCWebPage class.
      There's a key symbol called __gc immediately preceding the class keyword, which tells the C++ compiler that the ManagedCWebPage class is to be garbage collected. That is, instances of ManagedCWebPage will be managed by the runtime.
      The rest of the C++ syntax should look pretty familiar. The ASPX page defines a button, dropdown list, label, and textbox. The programmatic counterparts to each of these elements are defined as member variables near the top of the class. If you've been writing a lot of C# code lately, you may be surprised that the member variables representing the controls are declared as pointers in this C++ code. The C++ syntax only understands the managed types when they're declared as pointers. Remember, C# doesn't have the natural pointer syntax that C++ does.
      The ManagedCWebForm class implements a couple of event handlers: one for the Page_Load event and one for the SubmitEntry event (when the user presses the SubmitEntry button). The Page_Load event is called every time a client posts to the server. The System.Web.UI.Page class includes the member property IsPostBack for determining if the session is new or existing. If IsPostBack is true, then the user is posting back during an existing session. Otherwise, it's a new session. SubmitEntry extracts the name of the user from the textbox, the item selected from the dropdown list, and sets the Text field of the Label control accordingly. The syntax for each of these methods appears similar to the syntax you would see in equivalent C# code. Notice the arguments are passed as pointers. That's because the Object and EventArgs parameters are managed types.
      To get the page working, just build the assembly and make sure the assembly lands in the \bin directory under the virtual directory containing the ASPX code.

Conclusion

      If you're an experienced ASP developer accustomed to writing COM code to get your pages working, the CLR offers a breath of fresh air. Because all the code living under the CLR automatically agrees upon such issues as data typing, parameter order on the stack, and where to find method signatures within code (it's all described within the metadata), all the old boundary issues that COM was designed to solve disappear.
      To create code that runs under the CLR, you simply need a compiler that will generate Microsoft intermediate language (MSIL), for instance C# and Visual Basic .NET. Most developers currently using Visual Basic will probably stick with Visual Basic .NET. C# offers a great curly-brace syntax for producing MSIL, and many developers are becoming enamored of C# syntax. So why would you use C++?
      There are several reasons. First, you may have a huge amount of working legacy C++ code. In some cases it may be much easier to compile your DLLs as Managed C++ assemblies. For example, you might have code that represents particularly obfuscated logic that you have to keep running in your system. Another reason is that you just may not be ready to make the jump to C#. By and large, C# represents a cleaner syntax than C++ does; for example, it doesn't have any funny pointer syntax. However, C# does take a little bit of getting used to. The final, and perhaps most compelling reason to use Managed C++, is that the Microsoft C++ compiler is optimized. It's the most evolved and best-tuned compiler available for generating code to run under the CLR.
      This month I looked at what it takes to write a code-behind page in Managed C++. In later columns I'll revisit the topic of using Managed C++ in other parts of an ASP.NET page.

Send questions and comments for George to asp-net@microsoft.com..
George Shepherd writes .NET development tools with SyncFusion. He teaches short courses with DevelopMentor and is the author of a number of programming titles, including Applied .NET (Addison-Wesley, 2001). George may be reached at georges@syncfusion.com.