Memmexx Web Server Walkthrough

Introduction

The Memmexx web server is a .Net dll that provides web server functionality for any .Net program.  It is open-source, and thus can be modified to suit the needs of the developer.  One only need to reference its dll or include the Memmexx web server code in a solution.

 

This document walks the programmer through the task of creating a simple web server with some CGI functionality.  More documentation will exist when the author gets over his Wii addiction.  ;)

 

The Memmexx web server is untested in Mono.  The programmer prefers Stereo for its more lifelike representation of music.

 

A sample of the walkthrough is present in this distribution.  The reader must read the last part of the walkthrough to learn how to configure the web server.

License

The Memmexx web server is released under the BSD license:

 

Copyright (c) 2007, Andrew Rondeau

 

All rights reserved.

 

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions
are met:

 

Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

 

Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

 

Neither the name of the Andrew Rondeau nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.

 

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Overview, Contact Information, ect

The Memmexx web server was created by Andrew Rondeau.  You can contact him at http://www.andrewrondeau.com.

 

This is the only documentation that currently exists for the Memmexx web server.

 

This documentation assumes familiarity with C#, .Net, and Visual Studio.  While a new C# programmer might be able to follow this document; a programmer should have some C# experience before using the Memmexx Web Server.

 

Some familiarity with web technologies is assumed.  Specifically, the programmer should understand basic HTML and forms.

 

Please be aware that the Memmexx web server is not guaranteed to correctly conform to any standard, or to be free of defects.  It is tested with daily use from Safari and Internet Explorer 7.  It has not had any load testing.

Creating the Solution

We will create a web server that runs in the console.  In Visual Studio, navigate to File -> New -> Project.  Select Visual C# -> Windows -> Console Application.

 

 

Cleanup and Referencing the Dll

In the Solution Explorer, right-click on References and select ?Add Reference?.

 

On the ?Browse? tab, select Memmexx.WebServer.dll.

 

Coding

Yak-Shaving

Before we can start writing some simple web server code, we must shave a few yaks.

 

Add a ?using Memmexx.WebServer;? to Program.cs.

 

Add a class named WalkthroughWebServer.

 

Add a ?using Memmexx.WebServer?, inherit from the ?Session? class, and implement an empty CloseSession() method.

 

About the Session Base Class

The Memmexx web server provides some simple session management functionality, through Cookies.  (It is also possible to pass session IDs through get arguments, but that won?t be documented until after I beat Zelda on the Wii!)

 

What happens is that when a web browser opens up a page served by the Memmexx web server, a new Session object is created.  (In this walkthrough, we will use WalkthroughWebServer.)  For each subsequent request, the session cookie is used to find the appropriate Session object.

Session objects expire after 15 minutes of inactivity.  When this happens, CloseSession() is called, and the object is eligible for garbage collection.

 

It is important to remember the following:

?      Each unique user has a unique session object.

?      The session is identified by a cookie stored in the user?s web browser.

?      Session objects are closed and garbage collected after 15 minutes of inactivity.

 

What happens if there is a request for an expired (or non-existent) session?  Nothing!  A new one is created!  For complex web applications, the programmer must use care to trap errors that can occur when a session expires.  (There is a section at the end to describe how the Memmexx web server supports error handling.)

 

Starting up the Web Server

Now that we have created an empty implementation of the Session class, we need to do the following tasks:

 

Our web server will be rather, uhm, basic, at this point.

 

To do this, we will create a WebServer object and then call its RunServer() method.

 

Run the program.  (Push F5)

 

Navigate to ?localhost? in Internet Explorer.

 

The program?s console output will show some debugging information.

You will see a pending request.  This is okay; the Memmexx web server will keep a connection alive if the browser supports such behavior.

 

In the browser, there will be an error.  There is no index.html to serve!  This situation will soon be remedied.

Creating Some Content

We will now create some static and dynamic content.

 

First, stop the program.

 

In the solution explorer, right-click on the ?Walkthrough? project and select Add -> New Item

 

Select ?HTML Page? and name the file ?Index.html?

(Note: the default extension is .htm.  Make sure that .html is used.)

 

Put some text on the web page:

 

We will now point the web server to the directory where the ?index.html? file resides.  Typically, Visual Studio runs the executable in a subdirectory of a subdirectory of where the project resides, thus we will use ?..\..?.  In the event of an error, this directory can be hardcoded to wherever you put the project.

 

To do this, modify the constructor for the WebServer class in Program.cs.

 

Run the program and refresh the web browser.  (Point it to localhost)  Note:  Due to some funny behavior in Internet Explorer, Refresh might not work.  If it doesn?t work, click inside the address box and hit enter; or restart Internet Explorer.

 

Creating your first Dynamic Content

 

We will add a form that adds two numbers.

 

In Index.html, add a form that has two text boxes and a submit button.  In this example, we will name the text boxes ?num1? and ?num2?.  The action of the form is ?Add.420?, and the method is ?get?.

 

 

Save the page and refresh the web browser.  There is no need to restart the program.

 

You might have noticed that if you click on ?Submit Query?, there is an error.  This is because the dynamic code isn?t added to the web server yet!

 

Stop the web server.

 

Add a function to WalkthroughWebServer that takes no arguments and returns an object of type WebResults.  It must have an attribute named [WebCallable].

 

This is an important point that must be emphasized:  The Memmexx web server allows the Session class to have methods that are directly called as the result of a Form.  All functions that can be called directly from a Form must meet the following requirements:

 

The extension of the form?s action must be .420.  (In this case, the action is ?Add.420?.)

 

Here is a simple version of Add().  (There is no error handling; this will be left as an exercise for the reader.)

[WebCallable]

public WebResults Add()

{

    // Convert the get parameters (which are strings) into numbers

    float num1 = int.Parse(SafeGetParameters["num1"]);

    float num2 = int.Parse(SafeGetParameters["num2"]);

    float sum = num1 + num2;

 

    // This type of WebResults object automatically creates a page to display from Strings

    return WebResults.FromString.CreateFromTitleAndBodyText(

        this,

        "Results of addition",

        sum.ToString());

}

 

 

Start the program.  There is no need to refresh the browser, because there are no html changes.

 yields

 

Some additional notes:

 

Adding Dynamic Content to HTML

 

A powerful feature of web development tools like ASP and PHP is their ability to call dynamic code from within HTML.  The Memmexx web server allows an HTML page to call functions as well.

 

Add the following to Index.html:

 

@#_MyDymanicFunction_These are the arguments!_#@

 

Function calls are worth explaining:

 

Just like Add(), a function named MyDymanicFunction must be added to the WalkthroughWebServer class.  This function follows similar rules:

 

Here is a sample of MyDynamicFunction:

[WebCallable]

public string MyDymanicFunction(string arguments)

{

    return

        "<em>MyDymanicFunction was called with</em><font size=\"+1\"> \""

        + arguments + "\" </font><em>as the argument</em>";

}

 

Note this function in the debugger:

 

(The arguments variable contains the arguments that we put into index.html.)

 

Function calls can be recursive; that is, a function can return a function call encoded in the @#_..._..._#@ format, and it will be called.  (This is an advanced topic that the programmer will hopefully someday show, hopefully after he?s done collecting all the yak hair stuck in his teeth.)

 

Auto-replacing variables with their values

 

The Memmexx web server allows a web page to access properties of objects used inside of objects available to a [WebCallable] function.

 

For this example, we will create a small class and two functions:

public class ActiveParseExample

{

    public ActiveParseExample(int num, string str)

    {

        _Num = num;

        _String = str;

    }

 

    public int Num

    {

        get { return _Num; }

    }

    private int _Num;

 

    public string String

    {

        get { return _String; }

    }

    private string _String;

}

 

[WebCallable]

public string ActiveParseEnumeration(string arguments)

{

    ActiveParseExample[] apes = new ActiveParseExample[] {

        new ActiveParseExample(1, "one"),

        new ActiveParseExample(2, "two"),

        new ActiveParseExample(3, "three")};

 

    // Use a StringBuilder to build the response

    StringBuilder toReturn = new StringBuilder();

    foreach (ActiveParseExample ape in apes)

    {

        string part = ReplaceVarsWithValues(arguments, ape);

        toReturn.Append(part);

    }

 

    return toReturn.ToString();

}

 

[WebCallable]

public string ActiveParseSingle(string arguments)

{

    return ReplaceVarsWithValues(arguments, new ActiveParseExample(0, "single"));

}

 

We will also add the following to index.html:

<p><em>Example of auto-replace in an enumeration:</em><br />

@#_ActiveParseEnumeration_Num: [_Num_], String: [_String_]<br />_#@</p>

 

<p><em>Example of auto-replace for a single value:</em><br />

@#_ActiveParseSingle_Num: [_Num_], String: [_String_]<br />_#@</p>

 

 

ReplaceVarsWithValues() is a function in the base session class.  It takes a string and an object as arguments.  Wherever the string has a property name in [_..._] format, it replaces it with the value of the property.  (If the property isn?t a string, it calls ToString()).  Thus, all instances of [_Num_] are replaced with the ActiveParseExample object?s value for the Num property.

 

Start the program and refresh the web browser:

 

A note on recursion:  The will replace [(_foo_)] with [_foo_], and [((_bar_))] with [(_bar_)].

Error Handling

 

The Memmexx web server supports two kinds of methods for gracefully handling errors that can occur at runtime.  Some errors may occur if a request assumes that the session is in a certain state.  (This may happen when a session expires.)  Other errors may occur due to security violations.  Memmexx?s methods for handling errors work through exceptions, and are as follows:

 

For all other exceptions, the Memmexx web server informs the user that an error occurred and displays NO INFORMATION from the exception object.  This is because some lower-level exceptions often contain information that is helpful to hackers.  If more useful debugging information is desired, the Memmexx web server will display debugging information when built in Debug mode.  One can either include the Memmexx.WebServer project in the solution, or build it from source code.  (Building the Memmexx web server is not documented here.)  DO NOT USE THE DEBUG VERSION OF THE MEMMEXX WEB SERVER IN A PRODUCTION ENVIRONMENT ON THE PUBLIC INTERNET.  YOU HAVE BEEN WARNED!!!

 

These examples assume some savvy-ness with web programming.  In both cases, we?ve added function calls to Index.html.  The functions check for the presence of Get arguments, which are hard-coded into the hyperlink.

An example of WebResultsOverrideException

 

Add the following function to the WalkthroughWebServer class:

 

[WebCallable]

public string WebResultsOverrideExample(string arguments)

{

    // We will use a Get parameter to indicate that this exception should be thrown

    if (SafeGetParameters.ContainsKey("WebResultsOverrideExample"))

    {

        WebResults webResults = WebResults.FromString.CreateFromTitleAndBodyText(

            this,

            "Example of WebResultsOverride",

            "Example of WebResultsOverride");

 

        throw new WebResultsOverrideException(

            webResults,

            "This is an example of using the WebResultsOverrideException");

    }

 

    // Otherwise, return nothing

    return "";

}

 

Add the following to Index.html:

@#_WebResultsOverrideExample__#@<a href="index.html?WebResultsOverrideExample=1">Test WebResultsOverrideExample()</a><br />

 

To test, click on the new link.

An Example of SafeException

 

Add the following function to the WalkthroughWebServer class:

 

[WebCallable]

public string SafeExceptionExample(string arguments)

{

    // We will use a Get parameter to indicate that this exception should be thrown

    if (SafeGetParameters.ContainsKey("SafeExceptionExample"))

        throw new SafeException("SafeException example");

 

    // Otherwise, return nothing

    return "";

}

 

Add the following to Index.html:

 

@#_SafeExceptionExample__#@<a href="index.html?SafeExceptionExample=1">Test SafeExceptionExample()</a><br />


 

To test, click on the new link.