Question

Has anyone used Mono, the open source .NET implementation on a large or medium sized project? I'm wondering if it's ready for real world, production environments. Is it stable, fast, compatible, ... enough to use? Does it take a lot of effort to port projects to the Mono runtime, or is it really, really compatible enough to just take of and run already written code for Microsoft's runtime?

Was it helpful?

Solution

There are a couple of scenarios to consider: (a) if you are porting an existing application and wondering if Mono is good enough for this task; (b) you are starting to write some new code, and you want to know if Mono is mature enough.

For the first case, you can use the Mono Migration Analyzer tool (Moma) to evaluate how far your application is from running on Mono. If the evaluation comes back with flying colors, you should start on your testing and QA and get ready to ship.

If your evaluation comes back with a report highlighting features that are missing or differ significantly in their semantics in Mono you will have to evaluate whether the code can be adapted, rewritten or in the worst case whether your application can work with reduced functionality.

According to our Moma statistics based on user submissions (this is from memory) about 50% of the applications work out of the box, about 25% require about a week worth of work (refactoring, adapting) another 15% require a serious commitment to redo chunks of your code, and the rest is just not worth bothering porting since they are so incredibly tied to Win32. At that point, either you start from zero, or a business decision will drive the effort to make your code portable, but we are talking months worth of work (at least from the reports we have).

If you are starting from scratch, the situation is a lot simpler, because you will only be using the APIs that are present in Mono. As long as you stay with the supported stack (which is pretty much .NET 2.0, plus all the core upgrades in 3.5 including LINQ and System.Core, plus any of the Mono cross-platform APIs) you will be fine.

Every once in a while you might run into bugs in Mono or limitations, and you might have to work around them, but that is not different than any other system.

As for portability: ASP.NET applications are the easier ones to port, as those have little to no dependencies on Win32 and you can even use SQL server or other popular databases (there are plenty of bundled database providers with Mono).

Windows.Forms porting is sometimes trickier because developers like to escape the .NET sandbox and P/Invoke their brains out to configure things as useful as the changing the cursor blinking rate expressed as two bezier points encoded in BCD form in a wParam. Or some junk like that.

OTHER TIPS

It has pretty extensive coverage up to .NET 4.0 and even include some features from .NET 4.5 APIs, but there are a few areas that we have chosen not to implement due to the APIs being deprecated, new alternatives being created or the scope being too large. The following APIs are not available in Mono:

  • Windows Presentation Foundation
  • Windows Workflow Foundation (neither of the two versions)
  • Entity Framework
  • The WSE1/WSE2 "add-ons" to the standard Web Services stack

Additionally, our WCF implementation is limited to what Silverlight supported.

The easiest way to check for your specific project is to run the Mono Migration Analyzer (MoMA). The benefit is that it will notify the Mono team of issues which will prevent you from using Mono (if any), which lets them prioritize their work.

I recently ran MoMA on SubSonic and found only one issue - a weird use of Nullable types. That's a big codebase, so the coverage there was pretty impressive.

Mono is in active use in several commercial as well as open source products. It's in use in some large applications, such as Wikipedia and the Mozilla Developer Center, and has been used in embedded applications such as the Sansa MP3 players and powers thousands of published games.

At the language level, the Mono compiler is fully compliant with the C# 5.0 language specification.

On the desktop side, Mono works great if you commit to using GTK#. The Windows.Forms implementation is still a little buggy (for example, TrayIcon's don't work) but it has come a long way. Besides, GTK# is a better toolkit than Windows Forms as it is.

On the web side, Mono has implemented enough of ASP.NET to run most sites perfectly. The difficulty here is finding a host that has mod_mono installed on apache, or doing it yourself if you have shell access to your host.

Either way, Mono is great, and stable.

Key things to remember when creating a cross platform program:

  • Use GTK# instead of Windows.Forms
  • Ensure to properly case your filenames
  • Use Path.Separator instead of hardcoding "\", also use Environment.NewLine instead of "\n".
  • Do not use any P/Invoked calls to Win32 API.
  • Do not use the Windows Registry.

I personally use Mono in a prime-time env. I run mono servers dealing with giga-bytes of udp/tcp data processing related tasks and couldn't be happier.

There are peculiarities, and one of the most annoying things is that you can't just "build" your msbuild files due to Mono's current state:

  • MonoDevelop (the IDE) has some partial msbuild support, but will basically bork on any "REAL" build conf beyond a simple hello-world (custom build tasks, dynamic "properties" like $(SolutionDir), real configuration to name a few dead-ends)
  • xbuild which SHOULD have been the mono-supplied-msbuild-fully-compatible-build-system is even more horrible, so building from the command line is actually a worse experience than using the GUI, which is a very "unorthodox" state of the union for Linux environments...

Once/During getting your stuff actually BUILT, you might see some wildernesses even for code that SHOULD be supported like:

  • the compiler getting borked on certain constructs
  • and certain more advanced/new .NET classes throwing un-expected crap at you (XLinq anyone?)
  • some immature runtime "features" (3GB heap limit ON x64... WTF!)

but heaving said that generally speaking things start working very quickly, and solutions/workarounds are abundant.

Once you've gone over those initial hurdles, my experience is that mono ROCKS, and keeps getting better with every iteration.

I've had servers running with mono, processing 300GB of data per day, with tons of p/invokes and generally speaking doing LOTS of work and staying UP for 5-6 months, even with the "bleeding edge" mono.

Hope this helps.

The recommendations for the accepted answer are a little out of date now.

  • The windows forms implementation is pretty good now. (See Paint-Mono for a port of Paint.net which is a pretty involved Windows forms application. All that was required was an emulation layer for some of the P-Invoke and unsupported system calls).
  • Path.Combine as well as Path.Seperator to join paths and filenames.
  • The windows Registry is OK, as long as you are only using it for storing and retrieving data from your applications (i.e. you can't get any information about Windows from it, since it is basically a registry for Mono applications).

If you want to use WPF you'rr out of luck Mono currently has no plans to implement it.

http://www.mono-project.com/WPF

Well, mono is great, but as far as I can see, it is unstable. It works, but faults when you give mono process a serious work to do.

TL;DR - Do not use mono if you :

  • use AppDomains (Assembly Load\Unload) in multithreaded environments
  • Can't sustain 'let-it-fail' model
  • Experience occasional heavy-load events during process run

So, the facts.

We use mono-2.6.7 (.net v 3.5) on RHEL5, Ubuntu, and, to my point of view, it is most stable version built by Novell. It has an issue with Unloading AppDomains (segfaults), however, it fails very rare and this, by far, is acceptable (by us).

Okay. But if you want to use features of .net 4.0, you have to switch to versions 2.10.x, or 3.x, and that's where problems begin.

Compared to 2.6.7, new versions are just unacceptable to be used. I wrote a simple stress test application to tests mono installations.

It is here, with instructions to use : https://github.com/head-thrash/stress_test_mono

It uses Thread Pool Worker Threads. Worker loads dll to AppDomain and tries to do some math-work. Some of work is many-threaded, some is single. Almost all work is CPU-bound, although there are some reads of files from disk.

Results are not very good. In fact, for version 3.0.12:

  • sgen GC segfaults process almost immediatly
  • mono with boehm lives longer (from 2 to 5 hours), but segfaults eventually

As mentioned above, sgen gc just does not work (mono built from source):

* Assertion: should not be reached at sgen-scan-object.h:111

Stacktrace:


Native stacktrace:

    mono() [0x4ab0ad]
    /lib/x86_64-linux-gnu/libpthread.so.0(+0xfcb0) [0x2b61ea830cb0]
    /lib/x86_64-linux-gnu/libc.so.6(gsignal+0x35) [0x2b61eaa74425]
    /lib/x86_64-linux-gnu/libc.so.6(abort+0x17b) [0x2b61eaa77b8b]
    mono() [0x62b49d]
    mono() [0x62b5d6]
    mono() [0x5d4f84]
    mono() [0x5cb0af]
    mono() [0x5cb2cc]
    mono() [0x5cccfd]
    mono() [0x5cd944]
    mono() [0x5d12b6]
    mono(mono_gc_collect+0x28) [0x5d16f8]
    mono(mono_domain_finalize+0x7c) [0x59fb1c]
    mono() [0x596ef0]
    mono() [0x616f13]
    mono() [0x626ee0]
    /lib/x86_64-linux-gnu/libpthread.so.0(+0x7e9a) [0x2b61ea828e9a]
    /lib/x86_64-linux-gnu/libc.so.6(clone+0x6d) [0x2b61eab31ccd]

As for boehm segfauls - for example (Ubuntu 13.04, mono built from source):

mono: mini-amd64.c:492: amd64_patch: Assertion `0' failed.
Stacktrace:
at <unknown> <0xffffffff>
at System.Collections.Generic.Dictionary`2.Init (int,System.Collections.Generic.IEqualityComparer`1<TKey>) [0x00012] in /home/bkmz/my/mono/mcs/class/corlib/System.Collections.Generic/Dictionary.cs:264
at System.Collections.Generic.Dictionary`2..ctor () [0x00006] in /home/bkmz/my/mono/mcs/class/corlib/System.Collections.Generic/Dictionary.cs:222
at System.Security.Cryptography.CryptoConfig/CryptoHandler..ctor (System.Collections.Generic.IDictionary`2<string, System.Type>,System.Collections.Generic.IDictionary`2<string, string>) [0x00014] in /home/bkmz/my/mono/mcs/class/corlib/System.Security.Cryptography/Crypto
Config.cs:582
at System.Security.Cryptography.CryptoConfig.LoadConfig (string,System.Collections.Generic.IDictionary`2<string, System.Type>,System.Collections.Generic.IDictionary`2<string, string>) [0x00013] in /home/bkmz/my/mono/mcs/class/corlib/System.Security.Cryptography/CryptoCo
nfig.cs:473
at System.Security.Cryptography.CryptoConfig.Initialize () [0x00697] in /home/bkmz/my/mono/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs:457
at System.Security.Cryptography.CryptoConfig.CreateFromName (string,object[]) [0x00027] in /home/bkmz/my/mono/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs:495
at System.Security.Cryptography.CryptoConfig.CreateFromName (string) [0x00000] in /home/bkmz/my/mono/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs:484
at System.Security.Cryptography.RandomNumberGenerator.Create (string) [0x00000] in /home/bkmz/my/mono/mcs/class/corlib/System.Security.Cryptography/RandomNumberGenerator.cs:59
at System.Security.Cryptography.RandomNumberGenerator.Create () [0x00000] in /home/bkmz/my/mono/mcs/class/corlib/System.Security.Cryptography/RandomNumberGenerator.cs:53
at System.Guid.NewGuid () [0x0001e] in /home/bkmz/my/mono/mcs/class/corlib/System/Guid.cs:492

Or (RHEL5, mono is taken from rpm here ftp://ftp.pbone.net/mirror/ftp5.gwdg.de/pub/opensuse/repositories/home%3A/vmas%3A/mono-centos5)

Assertion at mini.c:3783, condition `code' not met
Stacktrace:
at <unknown> <0xffffffff>
at System.IO.StreamReader.ReadBuffer () [0x00012] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System.IO/StreamReader.cs:394
at System.IO.StreamReader.Peek () [0x00006] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System.IO/StreamReader.cs:429
at Mono.Xml.SmallXmlParser.Peek () [0x00000] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/Mono.Xml/SmallXmlParser.cs:271
at Mono.Xml.SmallXmlParser.Parse (System.IO.TextReader,Mono.Xml.SmallXmlParser/IContentHandler) [0x00020] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/Mono.Xml/SmallXmlParser.cs:346
at System.Security.Cryptography.CryptoConfig.LoadConfig (string,System.Collections.Generic.IDictionary`2<string, System.Type>,System.Collections.Generic.IDictionary`2<string, string>) [0x00021] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System.Security.Cryptog
raphy/CryptoConfig.cs:475
at System.Security.Cryptography.CryptoConfig.Initialize () [0x00697] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs:457
at System.Security.Cryptography.CryptoConfig.CreateFromName (string,object[]) [0x00027] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs:495
at System.Security.Cryptography.CryptoConfig.CreateFromName (string) [0x00000] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs:484
at System.Security.Cryptography.RandomNumberGenerator.Create (string) [0x00000] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System.Security.Cryptography/RandomNumberGenerator.cs:59
at System.Security.Cryptography.RandomNumberGenerator.Create () [0x00000] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System.Security.Cryptography/RandomNumberGenerator.cs:53
at System.Guid.NewGuid () [0x0001e] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System/Guid.cs:483
at System.Runtime.Remoting.RemotingServices.NewUri () [0x00020] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System.Runtime.Remoting/RemotingServices.cs:356
at System.Runtime.Remoting.RemotingServices.Marshal (System.MarshalByRefObject,string,System.Type) [0x000ba] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System.Runtime.Remoting/RemotingServices.cs:329
at System.AppDomain.GetMarshalledDomainObjRef () [0x00000] in /usr/src/redhat/BUILD/mono-3.0.3/mcs/class/corlib/System/AppDomain.cs:1363

Both failures are somehow connected to AppDomains logic, so, you should stay away from them in mono.

BTW, tested program worked 24 hours on Windows machine in MS .NET 4.5 env without any fail.

So, in conclusion, I would like to say - use mono with caution. It works from the first glance, but can easily fail whenever. You'd be left with a bunch of core dumps and major faith loss in opensource projects.

MoMA is a great tool for this, as someone else suggested. The biggest sources of incompatibility these days are applications which DllImport (or P/Invoke) into Win32 libraries. Some assemblies aren't implemented, but most of them are Windows-only and really wouldn't make sense on Linux. I think it's fairly safe to say that most ASP.NET applications can run on Mono with limited modifications.

(Disclosure: I've contributed to Mono itself, as well as written apps that run on top of it.)

In many cases, you can take existing code and just run it on Mono, particularly if you're porting an ASP.NET application.

In some cases, you may require whole new sections of code to make it work. If you use System.Windows.Forms, for example, the application won't work unmodified. Likewise if you use any Windows-specific code (registry access code, for example). But I think the worst offender is UI code. That's particularly bad on Macintosh systems.

We've been using it for a project here at work that needed to run on Linux but reuse some .NET libraries that we built in Managed C++. I've been very surprised at how well it has worked out. Our main executable is being written in C# and we can just reference our Managed C++ binaries with no issue. The only difference in the C# code between Windows and Linux is RS232 serial port code.

The only big issue I can think of happened about a month ago. The Linux build had a memory leak that wasn't seen on the Windows build. After doing some manual debugging (the basic profilers for Mono on Linux didn't help much), we were able to narrow the issue down to a specific chunk of code. We ended up patching a workaround, but I still need to find some time to go back and figure out what the root cause of the leak was.

Do you know how good Mono 2.0 preview's support is for Windows Forms 2.0?

From the little bit that I've played with it, it seemed relatively complete and almost usable. It just didn't quite look right in some places and is still a little hit or miss overall. It amazed me that it worked as well as it did with some of our forms, though honestly.

Yes it definitely is (if you're careful though) We support Mono in Ra-Ajax (Ajax library found at http://ra-ajax.org) and we're mostly not having problems at all. You need to be careful with some of the "most insane things" from .Net like WSE etc, and also probably quite some few of your existing projects will not be 100% Mono compatible, but new projects if you test them during development will mostly be compatible without problems with Mono. And the gain from supporting Linux etc through using Mono is really cool ;)

A large portion of the secret of supporting Mono I think is to use the right tools from the beginning, e.g. ActiveRecord, log4net, ra-ajax etc...

For the type of application we're building Mono unfortunately doesn't seem ready for production. We were impressed with it overall, and impressed with its performance both on Windows and on EC2 machines, however, our program crashed consistenly with garbage collection errors on both Windows and linux.

The error message is: "fatal errors in GC: too many heap sections", here is a link to someone else experiencing the problem in a slightly different way:

http://bugzilla.novell.com/show_bug.cgi?id=435906

The first piece of code we ran in Mono was a simple programming challenge we'd developed... The code loads about 10mb data into some data structures (e.g. HashSets), then runs 10 queries against the data. We ran the queries 100 times in order to time them and get an average.

The code crashed around the 55th query on Windows. On linux it worked, but as soon as we moved to a bigger data set, it would crash too.

This code is very simple, e.g. put some data into HashSets and then query those HashSets etc, all native c#, nothing unsafe, no API calls. On the Microsoft CLR it never crashes, and runs on huge data sets 1000s times just fine.

One of our guys emailed Miguel and included the code that caused the problem, no response yet. :(

It also seems like many other people have encountered this problem without solution - one solution has been suggested to recompile Mono with different GC settings but that just appears to increase the threshold before which it crashes.

Just check www.plasticscm.com. Everything (client, server, GUI, merge tools) is written on mono.

It really depends on the namespaces and classes that you are using from the .NET framework. I had interest in converting one of my windows services to run on my email server, which is Suse, but we ran into several hard roadblocks with APIs that had not been completely implemented. There is a chart somewhere on the Mono website that lists all of the classes and their level of completion. If your application is covered, then go for it.

Like any other application, do prototyping and testing before you make a full commitment, of course.

Another problem we ran into is licensed software: if you are referencing someone else's DLL, you can't code your way around incompatibilities that are buried in that assembly.

I would imagine then if you have an application with some 3rd party components you may be stuffed. I doubt a lot of vendors will develop with Mono in mind

Example: http://community.devexpress.com/forums/p/55085/185853.aspx

No, mono is not ready for serious work. I wrote a few programs on Windows using F# and ran them on Mono. Those program used disk, memory and cpu quite intensively. I saw crashes in mono libraries (managed code), crashes in native code and crashes in the virtual machine. When mono worked the programs were at least two times slower than in .Net in Windows and used much more memory. Stay away from mono for serious work.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top