VB.net on Linux using Wine mixed with Mono C#

So I encountered some legacy VB.net code that I wanted to compile into a cool Nancy-based application that runs under Mono on Linux. After trying to compile my code with an outdated (2008?) Mono VB.net compiler and linking the result with my Mono C# (Nancy) project I got frustrated with the following error:

Mono.CSharp.InternalErrorException: Failed to import assembly `System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
---> System.ArgumentException: Value does not fall within the expected range.
at KVM.Reflection.Fusion.CompareAssemblyIdentityPure

So I tried to compile the VB.net code on Linux, not with Mono, but with the official compiler under Wine. The “winetricks” script makes it actually easy to install “.Net Framework 4”:

sudo apt-get install wine
rm -Rf ~/.wine
WINEARCH=win32 WINEPREFIX=~/.wine winecfg
wget http://winetricks.org/winetricks
chmod +x winetricks
./winetricks dotnet40

We can quickly test the installation with the compile command:

cd /home/maurits/projects/HelloWorld/VisualBasic
WINEDEBUG=-all wine c:\\windows\\Microsoft.NET\\Framework\\v4.0.30319\\vbc.exe "/out:VisualBasic.dll" /rootnamespace:VisualBasic /target:library "HelloModule.vb"

Our HelloModule.vb file looks like this:

Imports System

<Assembly: CLSCompliant(True)> 

Public Module HelloModule

	Public Function Hello() as String
		Dim s as String = "Hello World!"
		Return s
	End Function

End Module

Microsoft has a good article on Writing CLS-Compliant Code. These are the rules you have to follow when mixing code from different .net languages. The actual rules are described in a lengthy document titled: Language Independence and Language-Independent Components. Read it or remember this summary from stackoverflow:

  • Unsigned types should not be part of the public interface of the class. What this means is public fields should not have unsigned types like uint or ulong, public methods should not return unsigned types, parameters passed to public function should not have unsigned types. However unsigned types can be part of private members.
  • Unsafe types like pointers should not be used with public members. However they can be used with private members.
  • Class names and member names should not differ only based on their case. For example we cannot have two methods named MyMethod and MYMETHOD.
  • Only properties and methods may be overloaded, Operators should not be overloaded.

Simple right? In C# we will be “using” the VisualBasic DLL (dynamic link library) and it’s HelloModule like this:

using System;
using VisualBasic;

namespace ConsoleApplication1
{
	class ConsoleApplication1
	{
		public static void Main (string[] args)
		{
			Console.WriteLine (HelloModule.Hello());
		}
	}
}

We can actually build our entire solution using “MSBuild.exe” and the following command:

cd /home/maurits/projects/HelloWorld/
WINEDEBUG=-all wine c:\\windows\\Microsoft.NET\\Framework\\v4.0.30319\\MSBuild.exe HelloWorld.sln

Or we can build the individual projects:

WINEDEBUG=-all wine c:\\windows\\Microsoft.NET\\Framework\\v4.0.30319\\MSBuild.exe VisualBasic\\VisualBasic.vbproj
WINEDEBUG=-all wine c:\\windows\\Microsoft.NET\\Framework\\v4.0.30319\\MSBuild.exe ConsoleApplication1\\ConsoleApplication1.csproj

And finally we can also compile the Mono C# project (csproj file) using Mono’s “xbuild” tool:

xbuild ConsoleApplication1/ConsoleApplication1.csproj

If you use “MSBuild.exe” and you the following error when compiling your VB.net code:

vbc : Command line error BC2001: file 'C:\users\maurits\Temp\.NETFramework,Version=v4.0,Profile=Client.AssemblyAttributes.vb' could not be found

Or if you get the following error on your C# code:

CSC : error CS2001: Source file 'C:\users\maurits\Temp\.NETFramework,Version=v4.0,Profile=Client.AssemblyAttributes.cs' could not be found

Then you may want to add the following tag to your “csproj” or “vbproj” project file:

<Target Name="GenerateTargetFrameworkMonikerAttribute" />

You should add it just before the final “</Project>” tag. Why? No clue. Check out stackoverflow yourself, because I simply don’t understand it. You may have to remove the “obj” and “bin” directories before the error disappears.

Note that if you get the following warning (you most probably will):

warning MSB3644: The reference assemblies for framework ".NETFramework,Version=v4.0" were not found.

You get rid of it by installing “Microsoft Windows SDK for Windows 7 and .NET Framework 4” and only install “Intellisense and Reference Assemblies” as explained by Sean Killeen.

Happy coding!

Share

Web development in VB.net or C# on Linux with Nancy

nancy I will make my first Linux web application in Microsoft’s “.net” platform. Since I do not run Windows I am going to using Mono (“.net for Linux”) and the MonoDevelop IDE. I am not so much a fan of ASP.net, so I’ve chosen Nancy instead which is a light-weight and simple replacement of ASP.net.

Nancy is a lightweight web framework for the .Net platform, inspired by Sinatra. Nancy aims at delivering a low ceremony approach to building light, fast web applications.

Xamarin is the company that allows for cross-platform multi-target (iOS, Android, Mac & Windows) development in C#. They maintain a recent build of the MonoDevelop application (currently 5.5). This tutorial may either be used for programming in C# or VB.net on Linux. C# does have support for code completion, something VB.net is missing in MonoDevelop.

monodevelop

To install the Xamarin version we have to add the Xamarin key and the repository by executing the following commands in any Debian based Linux (like Ubuntu/Mint):

sudo apt-key adv --keyserver pgp.mit.edu --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list
sudo apt-get update

After that we can install everything using the following one-liner:

sudo apt-get install monodoc-base monodevelop mono-vbnc

Creating the project

After these installs (takes about 200 MB) you will have the “MonoDevelop” application (version 5.5) installed and you can start it from the “Development” menu. When you start it, it will ask you what you want to do. Choose to create an “Empty Project (VBNet)”. If you want to use C# then choose “Empty Project (C#)”.

error_project_dotnet_45

If you get an error stating “Error while trying to load the project”, “Project does not support framework ‘.NETFramework,Version=v4.5′”, then you may want to open the project XML file (either “test.vbproj” or “test.csproj”) and replace the value that is defined as the “TargetFrameworkVersion”:

<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>

becomes:

<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>

You can see below how that looks in my MonoDevelop:

traget_framework_version

And then we can go look for Nancy.Hosting.Self via Project > Add Packages

add_package_nancy

When the “Add packages” window opens type “Nancy.Hosting.Self” in the search field:

install_nancy

Select the package and click “Add Package” to add it to your project. Great! Now it is time for some code.

Nancy’s Hello World example

First we make sure we start our host. In the Application.vb file.

Option Explicit On
Option Strict On
 
Imports System

Public Class Application

  Public Shared Sub Main()
    Dim host As Nancy.Hosting.Self.NancyHost
    host = New Nancy.Hosting.Self.NancyHost(New Uri("http://localhost:8080"))
    host.Start()
    Console.ReadLine()
  End Sub

End Class

And then we create a new Class “HelloModule” and add this code to it.

Option Explicit On
Option Strict On

Imports System

Public Class HelloModule
    Inherits Nancy.NancyModule

    Public Sub New()
        Me.Get("/") = AddressOf Hello
    End Sub

    Public Function Hello(ByVal parameters as Object) As String
        Return "Hello world"
    End Function

End Class

If we use C# then the Application.cs file looks like this:

using System;

public class Application
{
    static void Main(string[] args)
    {
        Nancy.Hosting.Self.NancyHost host;
        host = new Nancy.Hosting.Self.NancyHost(new Uri("http://localhost:8080"));
        host.Start();
        Console.ReadLine();
    }
}

And we create a second class “HelloModule” with the following content.

using System;

public class HelloModule: Nancy.NancyModule
{
    public HelloModule ()
    {
        Get["/"] = hello;
    }

    public String hello(Object parameters)
    {
        return "Hello world";
    }
}

Running your Nancy application

If you press run and you might get the following error:

Error CS0246: The type or namespace name `Uri' could not be found.
Are you missing an assembly reference?

Click on “Project > Edit References”, then type “System” in the search field, select the reference and click “OK”. If you get the following error:

/usr/lib/mono/4.5/Microsoft.VisualBasic.targets: Error: Error executing task Vbc:
Argument cannot be null. Parameter name: pathToTool

In case you get the above mentioned error, again, go to “Build\General” and under the section “Build Engine” uncheck the “Use MSBuild build engine …”

no_msbuild

And now open a browser and go to: http://localhost:8080/

If the page does not load it maybe because the application already exited. This can be solved by clicking “Run on external console” under “Project > Options > Run > General”:

run_on_ext_console

And now press run, everything should work and you should see some “Hello World” magic!

Posting some data…

If you are using Mono’s VB.net compiler (vbnc) you cannot use “extension methods”. Unfortunately lots of functionality in Nancy actually depends on that. You may run into this first when you are trying to “Bind” the posted data to your “Model” using “Nancy.ModelBinding”. The error  you will get says:

Error VBNC30456: 'Bind' is not a member of 'HelloWorldApp.HelloModule'. (VBNC30456)

You can avoid using the “Bind” method by actually reading the values from the “Request.Form” dictionary using:

Model.Id = CType(Ctype(Request.Form("Id"),DynamicDictionaryValue).Value,Integer)

You can imagine it may become quite hard to build software when you cannot rely on the Nancy manual on their wiki nor the numerous Nancy examples on Github. If you use C#, then you are not facing these difficulties as the Mono C# compiler is much more advanced than the Mono VB.net compiler. For this reason I am looking at compiling the Nancy part in C# and the business logic in VB.net and running them in a single solution. Check out my next post on this topic!

Finally..

You will learn that the MonoDevelop environment works flawlessly for C#. You may be able to create a working application with it for VB.net, but that won’t be easy. It is not the missing code completion that makes it hard. Things like “extension methods” which Nancy uses, and are supported by the Mono runtime, are not supported by the Mono VB.net compiler (vbnc).

The Nancy framework will feel very familiar if you have experience with frameworks like Sinatra, Silex or Flask. Mono is great for programmers that prefer Linux and as long as you program in C# (and not VB.net) it does not limit your possibilities. If you are going to run Nancy code in a production environment, then you may want to read about running Nancy behind a Nginx webserver.

NB: If you like this article you may also want to look into running ASP.NET vNext on Linux as well explained by Graeme Christie.

Share

Tutorial: Apache 2.4 as reverse proxy

This post explains how to configure Apache 2.4 (the version that comes with Ubuntu 14.04) as a fully transparent reverse proxy. If you have a single website that has multiple paths that are actually run by different web applications then this tutorial may be for you.

reverse_proxy

The proxy will serve both web applications from their own virtual host configuration. These may be on the same machine as shown below using the loop-back addresses 127.0.0.1 and 127.0.0.2 or on different machines if you use their (internal) IP addresses.

Site: http://www.yourwebsite.com/
App1: http://www.yourwebsite.com/app1 = http://127.0.0.1/app1
App2: http://www.yourwebsite.com/app2 = http://127.0.0.2/app2

This is the directory structure in which I want to load the various web apps:

maurits@nuc:/var/www/html$ ll
total 28
drwxr-xr-x 4 root root  4096 Dec  1 21:43 ./
drwxr-xr-x 3 root root  4096 Apr 21  2014 ../
-rw-r--r-- 1 root root 11510 Apr 21  2014 index.html
drwxr-xr-x 2 root root  4096 Dec  1 21:45 app1/
drwxr-xr-x 2 root root  4096 Dec  1 21:45 app2/

In this tutorial we run the web applications on the same paths as on the proxy. This means that the web apps run in a subdirectory, even on the machines behind the proxy. This avoids the need of rewriting and thus keeps this setup simple and easy to debug.

Setting up the reverse proxy in Apache 2.4

What we are going to do is setup a reverse proxy. First we load the “proxy_http” module in Apache 2.4 using:

sudo a2enmod proxy_http
sudo service apache2 restart

Let’s setup the reverse proxy virtual host configuration in “/etc/apache2/sites-available/yourwebsite-proxy.conf” like this:

<VirtualHost *:80>
ServerName www.yourwebsite.com
DocumentRoot /var/www/html
ProxyPreserveHost On
ProxyPass /app1 http://127.0.0.1/app1
ProxyPass /app2 http://127.0.0.2/app2
</VirtualHost>

The virtual host configuration of app1 in “/etc/apache2/sites-available/yourwebsite-app1.conf” looks like this:

<VirtualHost 127.0.0.1:80>
ServerName www.yourwebsite.com
DocumentRoot /var/www/html
...
</VirtualHost>

And the virtual host configuration of app2 in “/etc/apache2/sites-available/yourwebsite-app2.conf” looks like this:

<VirtualHost 127.0.0.2:80>
ServerName www.yourwebsite.com
DocumentRoot /var/www/html
...
</VirtualHost>

Lets enable all sites and reload Apache using:

sudo a2ensite yourwebsite-proxy yourwebsite-app1 yourwebsite-app2
sudo service apache2 reload

Note that this works as the virtual host configurations with a specified IP address will be matched first. The “ProxyPreserveHost” will make sure the “Host” header in the request is not rewritten. The lack of a “ProxyPassReverse” will make sure that there is no rewriting done on the response.

Showing the correct remote IP address

It is important to understand that in the above setup, the proxied web application will only see a different “REMOTE_ADDR” environment variable, since there is absolutely no rewriting going on. The real visitor address is passed along in “X-Forwarded-For” header. This is a comma separated list and the last entry holds the real client IP address.

If you are on Apache 2.4, like in Ubuntu 14.04, you can correct the reported remote address by loading the “remoteip” module like this:

sudo a2enmod remoteip
sudo service apache2 restart

Add the “RemoteIPHeader” and “RemoteIPInternalProxy” directives to the virtual host configurations:

<VirtualHost 127.0.0.1:80>
ServerName www.yourwebsite.com
DocumentRoot /var/www/html
RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 127.0.0.0/8
...
</VirtualHost>

Note that the “RemoteIPInternalProxy” you must specify the internal IP address of the proxy. To test if you did it right you can run a PHP script that calls “phpinfo()”. If you see that the “REMOTE_ADDR” value is not set to the proxy, then it is working.

Adding headers to the upstream request

We want to make Apache2 add upstream headers and therefor we need to load the “headers” module in Apache 2.4 using:

sudo a2enmod headers
sudo service apache2 restart

Next, we have to adjust the reverse proxy virtual host configuration in “/etc/apache2/sites-available/yourwebsite-proxy.conf” like this:

<VirtualHost *:80>
ServerName www.yourwebsite.com
DocumentRoot /var/www/html
ProxyPreserveHost On
RewriteEngine On
RequestHeader add X-SSL off
RewriteRule ^/app1/(.*) http://127.0.0.1/app1/$1 [P,L]
RewriteRule ^/app2/(.*) http://127.0.0.2/app2/$1 [P,L]
</VirtualHost>

In this example we add a “X-SSL” header with the value “off” to the proxied request. If you want to add headers to the response you can use the “Header” directive.

If you have any questions, please use the comments below.

Share

Linux multi-player command line games (daemon-games)

snaked

Daemon-games is a set of multi-user console games for Linux. The name is a tribute to the well known Debian “bsdgames” package. A “daemon” is defined in Wikipedia as:

In multitasking computer operating systems, a daemon (/ˈdiːmən/ or /ˈdeɪmən/) is a computer program that runs as a background process, rather than being under the direct control of an interactive user. – Wikipedia

The first game in this series is multi-player snake and it is named “snaked” (the “d” is for daemon). You can see it in the screen-shot above. The next game I want to make is multi-player tetris (named “tetrisd”).

Implemented in C

This server is implemented in C. You can find the common code in the files “daemon.c” and “daemon.h”. It aims to be a simple implementation and that is why it is using the “select” call. The select call waits for input on a set of sockets (or file descriptors). When one of them has data the call returns and you can handle the socket(s) that have data. The server calculates the screens and sends them over in ANSI. It also calculates the differences between frames to reduce bandwidth. All user input is directly forwarded to the server.

Getting started with “snaked”

Running the server is as easy as:

git clone https://github.com/mevdschee/daemon-games
cd daemon-games
make
./snaked 9000

Running the client is as easy as:

wget https://raw.githubusercontent.com/mevdschee/daemon-games/master/client.sh
bash client.sh 127.0.0.1 9000

You should replace “127.0.0.1” by the IP address of the server. The number “9000” is the TCP port the server runs on. You can easily review the client to see that it actually just running netcat. You can play with the “wasd” keys and “q” for quit.

Download the source code

You can! Please play with it and send me improvements or make complete new games. I would love to accept any PR. All code is on GitHub:

https://github.com/mevdschee/daemon-games
Share

Play peg solitaire on the Linux command line

peg-solitaire

Peg solitaire rules

Peg solitaire is a very old game that you can play alone to kill some time. Classic versions are made of a wooden playfield with indentations for either wooden pegs or glass marbles on them. The objective is to remove one peg from the center and jump pegs until you have only one peg left in the center.

When one peg jumps over another peg, then the peg that you jumped over is removed from the playing field. The peg that made the jump is not removed and is now located either 2 positions up, left, right or down from it’s initial position. Diagonal jumps are not allowed, nor are jumps over multiple pegs at once.

Peg solitaire layouts

peg-solitaire_layouts

There are several layouts of the playing field. The picture above shows the layouts that are most common. The French layout is also called the “European” layout. Special about the European layout is that you cannot start and finish in the center, but you should start one peg above the center and end one peg below the center.

Implementation in C

I have written a Peg solitaire implementation in C for the Linux command line, just like I did with the 2048 game. It is again a single C file that you can easily compile with gcc and has no external dependencies. You can start the application with the layout name (from the picture above) as the first argument. If you did not provide any arguments the most common layout (English) is chosen.

wget https://raw.githubusercontent.com/mevdschee/peg-solitaire.c/master/peg-solitaire.c
gcc -o peg-solitaire peg-solitaire.c
./peg-solitaire french

Linux ANSI codes for command-line games

When you are going to write games for the command line you will probably need ANSI control sequences. ANSI control sequences allow you to: clear the screen, show or hide the cursor, move the cursor position, change the color of the characters and their background. Here is an overview of the most useful ANSI control sequences when creating console games:

printf("\e[2J");      // clear screen and move cursor to root
printf("\e[#;#H");    // move cursor to position #,# (default 1,1)
printf("\e[#A");      // move cursor # lines up (default 1)
printf("\e[#B");      // move cursor # lines down (default 1)
printf("\e[#C");      // move cursor # columns right (default 1)
printf("\e[#D");      // move cursor # columns left (default 1)
printf("\e[?25l");    // hide cursor
printf("\e[?25h");    // show cursor
printf("\e[0m");      // reset attributes (and color)
printf("\e[1m");      // set attribute bold
printf("\e[2m");      // set attribute half-bright
printf("\e[4m");      // set attribute underscore
printf("\e[7m");      // set attribute reverse video
printf("\e[21m");     // unset attribute bold
printf("\e[22m");     // unset attribute half-bright
printf("\e[24m");     // unset attribute underscore
printf("\e[27m");     // unset attribute reverse video
printf("\e[3#m");     // set foreground color to # (0-7)
printf("\e[4#m");     // set background color to # (0-7)
printf("\e[38;5;#m"); // set foreground color to # (0-255)
printf("\e[48;5;#m"); // set background color to # (0-255)

Check the ANSI palette script to see what colors are possible:

bash_256_colors

To get a good overview of supported codes in Linux read the man page:

man console_codes

Disable input buffering and local echo in Linux

Normally input is buffered and only when you press the “enter” key the input is readable from the standard input of the application. Also input is shown on the screen. When you are programming a game you don’t want this. You need to respond directly when a key is pressed and there is no need to display the pressed keys. This can be achieved by disabling input buffering and local echo. In C this is done with the following function:

#include <termios.h>
#include <stdbool.h>

void setBufferedInput(bool enable) {
	static bool enabled = true;
	static struct termios old;
	struct termios new;

	if (enable && !enabled) {
		// restore the former settings
		tcsetattr(STDIN_FILENO,TCSANOW,&old);
		// set the new state
		enabled = true;
	} else if (!enable && enabled) {
		// get the terminal settings for standard input
		tcgetattr(STDIN_FILENO,&new);
		// we want to keep the old setting to restore them at the end
		old = new;
		// disable canonical mode (buffered i/o) and local echo
		new.c_lflag &=(~ICANON & ~ECHO);
		// set the new settings immediately
		tcsetattr(STDIN_FILENO,TCSANOW,&new);
		// set the new state
		enabled = false;
	}
}

For the full source code check out: https://github.com/mevdschee/peg-solitaire.c

Share