Setup Mono, mod_mono, and Apache – An Introduction do Windows developers

First and foremost: I’m not a Linux developer, but I love using Linux to run my asp.net web applications through mono. And I use it more and more every month. So even though I might not be a Linux Wizard, I can probably help other Windows developers understand how to work on Linux. Anyway, here goes.

Installing Mono on Linux

I’m using the SUSE Linux distribution; specifically I’m using the 64 bit Amazon edition of Suse Linux. I’ve found it easier to deploy mono to Suse than other distributions. It might not be true anymore, and it might have been easier on other distributions if I knew more about Linux in general 🙂

However, installing mono under Suse is really easy.

First, you just have to add the relevant repository. Later we can install mono from this repository:

zypper addrepo http://download.mono-project.com/download-stable/openSUSE_11.4 mono-stable
zypper refresh --repo mono-stable

Important: You might experience that you are prompted to trust the repository key. Hit ‘a’ to always trust the key. Now upgrade the repository:

zypper dist-upgrade --repo mono-stable

Finally, install mono from the repository:

zypper install -y mono-complete

On my AWS Micro instance this takes a couple of minutes. This should do the trick. Type “mono –version” to ensure that mono has been installed.

Installing Apache with Mono on Linux

Now that Mono is installed, it is time to install the Apache Web Server. Apache works quite different from IIS, but you can actually come to appreciate it 🙂

We’ll start with the basic installation of Apache:

zypper install -y httpd
touch /etc/apache2/sysconfig.d/include.conf
rcapache2 start
zypper install -y xsp
zypper install -y mod_mono

In the first line httpd is installed. On Linux, things that ends with a “d” are usually “daemons” – somewhat equivalent to Windows services. So httpd is the Apache HTTP Daemon.

rcapache2 is a command for performing basic commands on Apache, for example the “start” command. It takes other parameters such as “stop” and “restart”.

Xsp is the mono web server. It can be nice to install for various testing purposes, but it shouldn’t be necessary. I usually always install it.

Finally the “mod_mono” component is the Apache module that runs mono. Apache plugins are often prefixed by “mod_”, for example mod_ssl.

Now that Apache is installed, we need to configure a VirtualHost on Apache. A VirtualHost is somewhat equivalent to a Virtual Directory in IIS. Actually the name VirtualHost probably makes more sense than Virtual Directory, I think.

Basically, the VirtualHost is given a PORT number, and you point it to some location on the file system. Anything ingoing on the specified port will then be executed by the web application running at the specified location on the file system. To glue these two together (to establish an actual runtime for executing your mono project), you need help from mod_mono. More on this below.

The VirtualHost is configured in a domain specific language which is almost an XML structure. In the beginning I found it hard to accept that this looks so much like XML, but it is far from being XML compliant. My advice is just to accept this. Yes, it’s ugly, but that’s how it is:-)

The actual file structure of the configuration files depends between the Linux distributions, but on Suse Linux the VirtualHosts are placed in the /etc/apache2/conf.d folder. Suse Linux is setup to automatically load all configuration files ending in .conf in the conf.d folder. So, go to this folder by typing:

cd /etc/apache2/conf.d

Create a file with a custom name ending in .conf – for example myWebServer.conf.

Open the file and paste this code (replace ServerName and ServerAdmin with your own values):

<VirtualHost *:80>
  ServerName ocase.net
  ServerAdmin mortenmaateDELETE_THIS@hotmail.com
  DocumentRoot /srv/www/mysite
  MonoServerPath mysite /usr/bin/mod-mono-server4
  MonoApplications mysite "/:/srv/www/mysite"
  <Location "/">
    Allow from all
    Order allow,deny
    MonoSetServerAlias mysite
    SetHandler mono
    SetOutputFilter DEFLATE
    SetEnvIfNoCase Request_URI "\.(?:gif|jpe?g|png)$" no-gzip dont-vary
  </Location>
  <IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/plain text/xml text/javascript
  </IfModule>
</VirtualHost>

Now, apache is configured with mod_mono. This VirtualHost will listen to all incoming traffic on port 80. You can specify the server name, the server admin in accordance with your own data.

The DocumentRoot directive is important and points to the folder on your file system that contains your web site. We haven’t created the web site yet, but we’ll do so in a minute. The MonoServerPath specifies which executable will run mod_mono. The number 4 signals, that we’re using the .NET 4 runtime. Mono has runtimes for other .NET versions as well.

The Location directive takes the parameter “/” which maps to the root location of the web site folder (specified in DocumentRoot above). Here some apache specific stuff can be set. I’ll cover the details of this in a later blog post.

Create your site

Allright, the DocumentRoot now points to a location on your server. In my code above it points to /srv/www/mysite. Create this folder and go to it by typing:

mkdir /srv/www/mysite
cd /srv/www/mysite

Create a file named index.html by typing:

echo "<h1>Hello world</h1>" >> index.html

Finally, you need to allow the webserver to access  the file and restart apache:

chmod 777 /srv/www/mysite -R
rcapache2 restart

Now you should be able to access your service in a normal browser, and it should return Hello World.

You can deploy your ASP.NET application to this folder, and it should work.

If you experience that changes you make are not taking effect, try restarting apache.

Making Apache start automatically on reboot

The Apache Daemon does not automatically start itself on boot. Often this is what you want for a web server. To enable this, type:

chkconfig --level 2345 apache2 on

 

Write csharp (C#) in command prompt console

I just found this mono tool today – it’s included in the mono installer.

If you’ve added your mono path to the environment variables, simply type csharp in the command prompt, and you’ll get:

C:\Documents and Settings\morm>csharp
Mono C# Shell, type "help;" for help

Enter statements below.
csharp>

And you’re good to go! I have a feeling that I’ll be using this feature extensively for both Mono and .NET development.

Amazon AWS Route 53 XSD’s

I’ve extracted some xsd’s for the route 53 api’s and uploaded them here:

http://www.box.net/shared/4pevbg7padukeganjya4

Next version of OCometNet

As you might know, OCometNet is a server to client notification framework.

Currently you can use it for chat applications.  But in the next version I’m working on extending this, so that it’s possible to update the view model on another client.

Check out this very short demo to see a preview of the upcoming functionality:

Registry settings in mono on Linux

Obviously, Linux does not have a registry. However, just like the .NET framework, Mono provides the Microsoft.Win32.Registry class for accessing the registry. So how does it work on Linux?

First, I would like to state that personally, I never use the registry. I hate using it for lots of reasons. But I do have situations where third party frameworks use the registry, and I use these framework on Mono/Linux, and hence I become dependent of it.

System wide settings

The system wide settings which are shared between users, e.g. HKCR, are stored in /etc/mono/registry. E.g. in /etc/mono/registry/ClassesRoot/. In this sub directory sub keys are stored as sub folders, and values are stored in xml files with the name values.xml:

<values>
<value name="Content Type"
type="string">application/msword</value>
</values>

This example is from /etc/mono/registry/ClassesRoot/.doc/values.xml.

User settings (e.g. HKCU) are stored in the same way, but in the sub folder  .mono/registry to the users home directory instead, e.g. ~/.mono/registry/CurrentUser.

Finally, if you are running a web app, please remember to ensure correct security settings if the web app should have access to specific or all registry settings. For example:

chmod 777 /etc/mono/registry/ClassesRoot -R

This will allow read and write access to ClassesRoot and all sub folders. Often you can loosen up on Linux registry settings security compared to Windows, but please remember to be careful.

Mono bug using custom model binder (IModelBinder)

Gosh, this one required an hour or two.

I use a custom model binder to parse the http body for some json.

The error I got was smth like a BAD REQUEST http error, and in apache’s error_log an entry said mth like: Invalid URI in request { myjson } PUT /MyUrl HTTP/1.1.

In my controller the code looks like this:

public JsonResult Update([ModelBinder(typeof(GenericModelBinder))]Case casefile) { … }

I resolved the problem by adding a default value for casefile, i.e.:

public JsonResult Update([ModelBinder(typeof(GenericModelBinder))]Case casefile = null) { … }

It must have something to do with the order of the routing – it seems that in mono the custom ModelBinder is applied in some step after the routing itself, and my request does not map to any URL –> route pattern since the ModelBinder graps stuff from the HTTP Body, and not from the url itself.

Anyway, now it works 🙂

Mono bug with dynamic key word (CS1061)

I had this bug: CS1061: Type `object’ does not contain a definition for [some property].

It took me a couple of hours to figure out that this is a minor bug in the “var” keyword in mono.

The problem occurs when “casting” a dynamic variable to var. In this process it is being treated as an Object by the compiler. E.g. something like:

dynamic d = some obj
var v = d;
v.MyProperty // CS1061 exception

In .NET, however, this works fine. To resolve the issue, rename the var keyword to dynamic.

Mono bug: No overload of JavaScriptSerializer.Deserialize() takes two arguments

Mono does not support the non-generic edition of this method. Use Deserialize(String input) instead.

Sub domains on IIS express

In the beginning I didn’t expect this would be difficult. And perhaps it is easier to set up if you are on a domain. However, in this scenario I’m not, and I’m not sure how much easier it would be if I was.

Anyway, FiddlerCore to the rescue. The solution is not perfect. It would be perfect if IIS Express could handle this for me, but it can’t. So perfect or not, I needed three steps:

  1. Setup FiddlerCore to capture all trafic for the sub domain, e.g. traffic for test.ocase.com
  2. Setup my application to handle sub domains and handle special cases when sub domains are redirected from Fiddler Core
  3. Manipulate the hosts file on the pc to listen to the sub domain, e.g. test.ocase.com

1. Setup FiddlerCore to capture all traffic for the sub domain test.ocase.com

First, I created a new HTTP Module. In the Init section, I placed this code:


if (!Fiddler.FiddlerApplication.IsStarted())
{
Fiddler.FiddlerCoreStartupFlags oFCSF = Fiddler.FiddlerCoreStartupFlags.Default;
Fiddler.FiddlerApplication.BeforeRequest += new Fiddler.SessionStateHandler(FiddlerApplication_BeforeRequest);

Fiddler.FiddlerApplication.Startup(m_Proxy.ListenToHttpPort, oFCSF);
}

Also, I inherited from IDisposable, and in the Dispose() method, I shut down Fiddler:


Boolean disposed;

public void Dispose()
{
if (!disposed)
{
if (Fiddler.FiddlerApplication.IsStarted())
Fiddler.FiddlerApplication.Shutdown();
disposed = true;
}
}

Finally, in the FiddlerApplication_BeforeRequest method, I placed this:

void FiddlerApplication_BeforeRequest(Fiddler.Session oSession)
{
if (oSession.host.ToLower().Contains("test.ocase.com"))
{
oSession.oRequest.headers.Add("proxyhost", oSession.host);
oSession.host = "http://ocase.com:8080";
}
}

This is where the magic happens. Here, I add a new HTTP header to the request with the key “proxyhost”. Whenever my sub domain is requested (contained in the oSession.host property), I handle the request.

I have one small obstacle, however. The HTTP 1.1 protocol specifies that the HTTP request should have a host header. The host header will contain the url including the sub domain. This means that when my browser requests test.ocase.com, it specifies this both in the URL and in the host header. So when fiddler redirects my request to “http://ocase.com:8080&#8221; (by specifying this in the oSession.host property), it will specify the url “http://ocase.com:8080&#8221; AND the host header “http://ocase.com:8080&#8221;. So, basically my sub domain is lost in the redirection process! To prevent this, I create a new HTTP header “proxyhost”, and here I set the value of the original host: “http://test.ocase.com&#8221; which includes the sub domain. I need to handle this in my application.

2. Setup my application to handle sub domains including sub domains with proxyhost
Basically, when I check out the sub domain in my application, I will first check to see if proxyhost is available. If it is, then I will use the sub domain specified in proxyhost. This will be the case when the sub domain is redirected through FiddlerCore. If it isn’t, no proxy is being used, thus no proxyhost is availble in the HTTP headers, and I’ll use the sub domain from the URL.

3. Manipulate the hosts file
The hosts file can be found here: %systemroot%\system32\drivers\etc\hosts. For example it could look like this:


# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
# 102.54.94.97 rhino.acme.com # source server
# 38.25.63.10 x.acme.com # x client host

# localhost name resolution is handled within DNS itself.
# 127.0.0.1 localhost
# ::1 localhost

127.0.0.1 ocase.com
127.0.0.1 test.ocase.com
127.0.0.1 test1.ocase.com
127.0.0.1 test2.ocase.com
127.0.0.1 ocase.ocase.com
127.0.0.1 test.localhost

I have added some sub domains for testing purposes, and I redirect all of them to the ip address of my localhost. This ensures that they are ultimately handled by my app. If I only change the host file and start my app, IIS Express will return an HTTP 400 Bad Request. But with FiddlerCore, the requests are captured at a lower level, and I can parse them correctly.

As with any other HTTP Module I can enable and disbale it in the web.config of my application. The examples posted in this blog post are really simple, but I ended up making it more generic obviously, and I also added more functionality such as logging and url redirection which I needed at a later stage in the development.

FiddlerCore – Fiddler.dll in your projects

I first heard of FiddlerCore on the Hearding Code pod cast recently. Now, you probably know Fiddler – at least for me, this is one of my favorite (free) web debugging tools on Windows. Baiscally, Fiddler captures all http traffic and lets you play around with it, step into the requests, tamper them etc. Cool stuff!

FiddlerCore is a (managed/.NET) dll that you can download and install along with a sample project from here: http://www.fiddler2.com/Fiddler/Core/. Actually, according to The Fiddler Father, Eric Lawrence, on the PodCast, this is not just the dll’s at the bottom of Fiddler, but a special compilation of the Fiddler dll’s that he maintains just for guys like us – thank you, Eric!

So far, my uses of this has been:

  • As a simple proxy redirecting http traffic to other ports
  • As a handler of sub domains on IIS Espress
  • As an http logging module
And I’ve only known about it for a month or so… It seems this was really something that I needed!
So far it works like a charm! I don’t know if it is stabile and fast enough to work in a prouction environment. For now I just use it for development purposes only, but for this it is certainly great.
I’ll write a separate blog post with some code on how to handle e.g. sub domains on IIS Express with Fiddler Core.