How to deploy Mono projects with Heroku

Last week I mentioned how I had successfully deployed Nancy / Mono (C# frameworks) onto Heroku.  This post covers how you can deploy your own Mono projects onto Heroku.

As before, this approach is completely unsupported by Heroku and I’m not 100% sure if it’s production ready. I would love to hear your experiences.

0) Prerequisites 
There are a few requirements before deploying a project.
    – The solution can compile using Mono on Linux (Ubuntu 10.04 – Lucid Lynx)
    – The launch application must be a self-hosted executable.
    – The self-hosted executable must stay alive and not exit. Example: https://github.com/BenHall/nancy-demo-hosting-self/blob/master/src/Program.cs#L20-23

1) Update heroku gem
Before you continue, make sure your running the latest heroku gem as you need the buildpack option which is only supported in later versions. Thanks Andy Pike for pointing this out.

$ gem update heroku

2) Listening to Heroku requests
This is the only part which I’m not too happy with. In order for Mono to accept Heroku requests, you need to bind the listener to the full hostname provided by Heroku – for example http://deep-moon-1452.herokuapp.com.

The application also needs to listen on a particular port randomly defined by Heroku. This is provided via an environment variable. 

Example:
https://github.com/BenHall/nancy-demo-hosting-self/blob/master/src/Program.cs#L12

Ironically this is the part which blocked me and after multiple combinations I was left with hard-coding the name as my last resort – see the commit https://github.com/BenHall/nancy-demo-hosting-self/commit/4d9e07bed92559a53b1463c37e837045d59c3a9a

3) How projects are built during deployment
Projects are built on Heroku during the git push process.  To find a solution to build, the command “ls $BUILD_DIR/*.sln | head -1” is used. This will return the name of the first solution file found.
Once the name has been determined, xbuild is called with the output streamed back. If the build fails, the deployment is stopped.

4) How the application is launched – Procfile
Once the project has been built, the self-hosted executable needs to be executed via a Procfile.

An example can be found here:
https://github.com/BenHall/nancy-demo-hosting-self/blob/master/Procfile

The web property specifies the command used by Heroku. The first part is the path to mono which is defined in the buildpack and shouldn’t be change. The second part is the relative path to your compiled executable.

In the example I also defined a local environment command allowing me to replicate the hosted environment locally via “foreman start local”. 

5) Creating the Heroku environment – Cedar and buildpacks
When creating your Heroku application to host your project, it’s important to specify the stack as cedar along with the buildpack for Mono. The buildpack defines the steps required to download Mono from my S3 account, configure the environment and build your solution.

$ heroku create --stack cedar --buildpack http://github.com/BenHall/heroku-buildpack-mono 

Remember to change the hostname your exe listens on otherwise you’ll received a Bad Request (Invalid Host) response.

If you receive the error “!Name must start with a letter and can only contain lowercase letters, numbers, and dashes” then make sure your using the latest Heroku gem (currently 2.18.1).

6) Push
A simple push should now be all you need.

$ git push heroku master

Done!  Technical details about how the buildpack works in a future post.

Important links:
Buildpack:  https://github.com/BenHall/heroku-buildpack-mono
Example: https://github.com/BenHall/nancy-demo-hosting-self

tl;dr: The main steps are
0) $ gem update heroku
1) $ git clone https://github.com/BenHall/nancy-demo-hosting-self
2) $ cd nancy-demo-hosting-self
3) $ heroku create --stack cedar --buildpack http://github.com/BenHall/heroku-buildpack-mono
4) Replace deep-moon-1452 in src/Program.cs to the application name created above
5) $ git commit -am "Changed application name"
6) $ git push heroku master
7) Tweet to say how amazing it is.

Mono XSP == OSX ASP.net Web Server

Over the weekend I required a very simple web server on my MacBook to allow me to play around with some iPhone Web App development. It didn’t need to do much, simply accept requests and serve webpages. While I’ve created web servers before, after sending a tweet out I was reminded about Mono XSP. XSP is an ASP.net web server developed under the Mono project banner allowing you to serve web pages and asserts (javascript, css, images etc) to clients. Simply – it’s great!

After installing Mono, to launch a server simply navigate to the directory where your pages resides using a Terminal (command prompt), and type in XSP. This will start a full webserver on port 8080 serving pages from the directory. Now, within seconds, I can quickly make any directory on my laptop accessible over HTTP!

On OSX, the execution simply looks like this:

Pretty:Base Ben$ xsp
xsp2
Listening on address: 0.0.0.0
Root directory: /Users/Ben/SourceControl/iPhoneWebApp101/iWebKit/Base
Listening on port: 8080 (non-secure)
Hit Return to stop the server.

Great for prototyping and rapid development and while I haven’t tried it, it should work on Windows equally as well.

Mono and File Paths

The joy of developing cross platform applications!!

When dealing with files and paths on a windows based platform you always use a backslash () as the path separator, for example ‘ConfigSettings.xml’. Append the full path onto the beginning and you would be able to load the settings.  However, if your application needs to run on top Linux or Mac OS X (Mono) then file paths are slightly different. Instead of ‘ConfigSettings.xml’ you need to use ‘Config/Settings.xml’. Notice the all important forward slash (/)! It’s a simple mistake to make and it can take a few moments to realise what the problem is. 

If you wanted to be really hard core (and correct), you would use Path.DirectorySeparatorChar property to define your separator. Alternatively, you might want to look at IOMap which should solve this mismatch problem for you.

Variations like this is a great reason why you should run your unitintegration tests on both platforms as part of your build.

Technorati Tags: