Copyright (c) 2004 by Charlie Calvert
This article explains how to get a standard CodeBehind ASP.NET program
up and running under Mono on Linux or Windows.
Mono is an open source implementation of Microsoft's .NET technology.
It is very much a work in progress, and so having the latest version is
important. The Mono team is going through the Microsoft .NET standard,
implementing each class and each method, one at a time, as fast as they
can. With each build, many ASP.NET standard functions are added to Mono.
If you are interested in Mono development on Linux, you should read my article
on installing the latest Mono code. Getting the latest build is important
if you want to have the widest possible range of code available to you
when you run your ASP.NET applications on Linux.
The Default Visual Studio 2003 or C#Builder ASP.NET Project
When you enter Visual Studio or C#Builder, and create a default ASP.NET Web
Application, you end up with four key files:
The first file, WebForm1.aspx, contains standard HTML code slightly
modified to support the ASP.NET standard. If that were the only file
in your project, then you would be in good shape, since either Mono's or
Microsoft's tools would automatically compile it for you. The other files,
however, are CSharp files that need to be compiled manually. It is the
compilation of these files that I believe needlessly discourages some Mono
developers.
The actual compilation of the files can be accomplished at the command
line with a single call to the Mono CSharp compiler
(mcs). The short file found in Listing 1 is a Linux
script that will perform the compilation. The same command will work in a
Windows batch file, but minus the first line which references the Linux
bash script engine. Note that the call to mcs, the Linux compiler, could all be
on one line. The code shown here will compile and run cleanly on Linux as
is, but you might want to place it all on one line in Windows. I have
broken the call to mcs into three lines with the backslash character in
order to make it more readable. You can remove the backslash character
and put the command all on one line.
Listing 1: A simple script for compiling an ASP.NET program created
in Visual Studio.
#! /bin/bash
mcs /t:library /out:WebApplication1.dll
-r:System.Web -r:System.Data -r:System.Drawing
AssemblyInfo.cs WebForm1.aspx.cs Global.asax.cs
On the first line of the call to mcs, the first argument (/t:library) tells the
compiler that you want to create a library. In Mono, libraries have a DLL
extension whether they are run on Windows or on Linux. The second
argument states that you want to create a library called
WebApplication1.dll. After the compilation is complete,
you should copy this file to a directory called bin,
which should be manually created one level further from the root of the
file system. The end result is that WebForm1.aspx will be one level
closer to the root than WebApplication1.dll:
/home/charlie/src/WebForm1.aspx
/home/charlie/src/bin/WebApplication1.dll
The second line of the call to mcs in Listing 1 specifies links to
the libraries that are needed to complete the compilation. A default
Visual Studio 2003 project depends on System.Web.dll, System.Data.dll
and System.Drawing.dll. By including these references in the script,
the Mono CSharp compiler knows to resolve the calls to these system
libraries.
The third line in the call to mcs lists the three CSharp source files
that you are generated by a default Visual Studio project. All three
files will be compiled and the resulting binary code will be stored in
WebApplication1.dll.
After executing this call to mcs, on either Linux or Windows, you
will end up with WebApplication1.dll. On my system, the file is 4608
bytes in size. As explained earlier, I copied this file to a directory
called bin, which is located one level further from the root of the
file system than WebForm1.aspx.
After compiling your ASP.NET project, you will want to run it. On
Linux, this is a fairly straight forward process. I will describe the
necessary steps in the next two sections of this article. The first
section is on Linux, the second on Windows.
Running Your ASP.NET Project in Linux
Mono comes with a special Web Server called xsp.exe. Starting the
server is very simple. On my system, I simply type mono
/usr/bin/xsp.exe at the shell prompt. The output from the command
looks like this:
[charlie@rohan MonoCodeBehind]$ mono
/usr/bin/xsp.exe Listening on port: 8080
Listening on address: 0.0.0.0
Root directory: /home/charlie/src/csharp/WebApps/MonoCodeBehind
Hit Return to stop the server.
By default, the server will start on port 8080. This means that you
do not have to shut down Apache, if you happen to have it running. Apache is, of course ,running on port
80. For now, you want the root directory to be the directory in which
you have stored your source files. In particular, it should be where
WebForm1.aspx is stored. xsp provides options for changing the root
directory or the port. You can see all the options by typing mono
/usr/bin/xsp.exe --help:
xsp.exe [--root rootdir] [--applications APPS] [--virtual virtualdir]
[--port N] [--address addr]
--port N: n is the tcp port to listen on.
Default value: 8080
AppSettings key name: MonoServerPort
--address addr: addr is the ip address to listen on.
Default value: 0.0.0.0
AppSettings key name: MonoServerAddress
--root rootdir: the server changes to this directory before
anything else.
Default value: current directory.
AppSettings key name: MonoServerRootDir
--applications APPS: a comma separated list of virtual directory and
real directory for all the applications we want to manage
with this server. The virtual and real dirs. are separated
by a colon.
Samples: /:.
the virtual / is mapped to the current directory.
/blog:../myblog
the virtual /blog is mapped to ../myblog
/:.,/blog:../myblog
Two applications like the above ones are handled.
Default value: /:.
AppSettings key name: MonoApplications
--nonstop: don't stop the server by pressing enter. Must be used
when the server has no controlling terminal.
--version: displays version information and exits.
You can now start Mozilla, and type in the following URL:
http://localhost:8080/WebForm1.aspx. Note that you have effectively
made the directory in which you stored WebForm1.aspx your root
directory for the Web Server. As a result, the URL is very
straightforward.
At this stage, you should see your ASP.NET program in your browser,
as shown in Figure 1. Please note that I have modified the default
project slightly to include a button and a text field.
Figure 1: A simple ASP.NET program running in the Mozilla browser
on RedHat Linux 9.0 with all the latest updates from the RedHat
Network and the Red Carpet mono channel.
Besides the XSP
WebBrowser described in this article, there is also a module add on to
Apache that has been created by the Mono project. Discussion of that
tool will be reserved for a later article.
Running Your ASP.NET Project in Windows
There is no special preparation that you need do to run your
project on Windows. If you have Microsoft's IIS server installed on
your system, then all you need to do is set up a virtual directory,
copy your files into it, and aim your browser at your copy of
WebForm1.aspx.
When setting up your project, remember to place WebApplication1.dll in a subdirectory one level further from the root
of the file system than the directory that holds WebForm1.aspx.
If WebForm1.aspx is in a virtual directory called MyWebForm, then you
should point your web browser at the following URL:
http://localhost/MyWebForm/WebForm1.aspx. The result should look very much
like what is shown in Figure 1. Note that I modified the default
VS or C#Builder project slightly to contain a text field and a button
so that you can see that the project actually does something.
To set up a virtual directory in IIS, run the snap-in administration tool for IIS (c:\windows\System32\inetsrv\inetmgr.exe). Right click on the Default Web Site and choose New | Virtual Directory to run a wizard. After completing the wizard, select the directory you created, right click to bring up its properties, and use the Application Setting to create an Application Name. The execute permissions for the directory can be left at Scripts only.
The Source
This article has been about how to get a default ASP.NET project up and
running in Mono. However, I think it is important to show you the actual source
files, even if I don't explain them in any detail. That way you can check
your source code against the code I created in order to confirm that you
are following all the steps correctly.
As you may have noticed in the screen shot, I did modify the default
project slightly by adding a button and text field, and code to respond to
clicks on the button by placing the word "Sam" in the text field. This
modifies the default project just enough so you can sense something
has been accomplished, without muddying the waters by adding complex code
not germane to the topic of this article.
The files needed in this project are shown in Listings 2 - 5.
Listing 2: The WebForm1.aspx file.
<%@ Page language="c#"
Codebehind="WebForm1.aspx.cs"
AutoEventWireup="false"
Inherits="WebApplication1.WebForm1" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>WebForm1</title>
<meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
<meta name="CODE_LANGUAGE" Content="C#">
<meta name="vs_defaultClientScript" content="JavaScript">
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="Form1" method="post" runat="server">
<asp:Button id="Button1"
style="Z-INDEX: 101;
LEFT: 144px;
POSITION: absolute;
TOP: 64px"
runat="server"
Text="Button">
</asp:Button>
<asp:TextBox id="TextBox1"
style="Z-INDEX: 102;
LEFT: 256px;
POSITION: absolute;
TOP: 72px"
runat="server">
</asp:TextBox>
</form>
</body>
</HTML>
Listing 3: The WebForm1.aspx.cs file.
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace WebApplication1
{
/// <summary>
/// Summary description for WebForm1.
/// </summary>
public class WebForm1 : System.Web.UI.Page
{
protected System.Web.UI.WebControls.TextBox TextBox1;
protected System.Web.UI.WebControls.Button Button1;
private void Page_Load(object sender, System.EventArgs e)
{
// Put user code to initialize the page here
}
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.Button1.Click += new System.EventHandler(this.Button1_Click);
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
private void Button1_Click(object sender, System.EventArgs e)
{
TextBox1.Text = "Neither fire nor wind, birth nor death can erase our good deeds.";
}
}
}
Listing 4: The Global.asax.cs file.
using System;
using System.Collections;
using System.ComponentModel;
using System.Web;
using System.Web.SessionState;
namespace WebApplication1
{
/// <summary>
/// Summary description for Global.
/// </summary>
public class Global : System.Web.HttpApplication
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
public Global()
{
InitializeComponent();
}
protected void Application_Start(Object sender, EventArgs e)
{
}
protected void Session_Start(Object sender, EventArgs e)
{
}
protected void Application_BeginRequest(Object sender, EventArgs e)
{
}
protected void Application_EndRequest(Object sender, EventArgs e)
{
}
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
}
protected void Application_Error(Object sender, EventArgs e)
{
}
protected void Session_End(Object sender, EventArgs e)
{
}
protected void Application_End(Object sender, EventArgs e)
{
}
#region Web Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
}
#endregion
}
}
Listing 5: The AssemblyInfo.cs file.
using System.Reflection;
using System.Runtime.CompilerServices;
//
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
//
[assembly: AssemblyTitle("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.*")]
//
// In order to sign your assembly you must specify a key to use. Refer to the
// Microsoft .NET Framework documentation for more information on assembly signing.
//
// Use the attributes below to control which key is used for signing.
//
// Notes:
// (*) If no key is specified, the assembly is not signed.
// (*) KeyName refers to a key that has been installed in the Crypto Service
// Provider (CSP) on your machine. KeyFile refers to a file which contains
// a key.
// (*) If the KeyFile and the KeyName values are both specified, the
// following processing occurs:
// (1) If the KeyName can be found in the CSP, that key is used.
// (2) If the KeyName does not exist and the KeyFile does exist, the key
// in the KeyFile is installed into the CSP and used.
// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
// When specifying the KeyFile, the location of the KeyFile should be
// relative to the "project output directory". The location of the project output
// directory is dependent on whether you are working with a local or web project.
// For local projects, the project output directory is defined as
// <Project Directory>obj<Configuration>. For example, if your KeyFile is
// located in the project directory, you would specify the AssemblyKeyFile
// attribute as [assembly: AssemblyKeyFile("....mykey.snk")]
// For web projects, the project output directory is defined as
// %HOMEPATH%VSWebCache<Machine Name><Project Directory>obj<Configuration>.
// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
// documentation for more information on this.
//
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("")]
[assembly: AssemblyKeyName("")]
Summary
In this article you have seen how to compile a default Visual Studio or
C#Builder CodeBehind ASP.NET project under Mono. It turns out not to be a
difficult task, so long as you understand the steps involved. The key
points to remember are that you need to use mcs to compile the CSharp
source files in your project, and that you should place resulting DLL in a
directory called bin that is one level further from the root than the
directory where your source is stored.