Running on Linux

As the F# Foundation states: “F# is a mature, open source, cross-platform, functional-first programming language”. Today I decided to try out the cross-platform part of that statement by trying to get my project running on Linux.

I’m running Ubuntu 16.10 64-bit with 3GB of RAM in VirtualBox. The steps below come from various sources, which are referenced by links.

F# Setup on Linux

Steps taken from and sites it references. All steps were run in a Terminal in Ubuntu.

Step 1. Add mono to apt sources

sudo apt-key adv --keyserver hkp:// --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
echo "deb wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list
sudo apt-get update

Step 2. Install Mono

sudo apt-get install mono-devel
sudo apt-get install mono-complete 

At this point I was able to create and run the hello.cs program as described here meaning Mono and therefore .NET was functioning on the machine.

Step 3. Finally, install fsharp

sudo apt-get install fsharp

Setting up the project

To get the project running we first needed the source code

git clone -b Suave FunctionalDomainProject
cd FunctionalDomainProject

and then to restore the libraries using paket. This came with a slight hiccup as linux needed to be told that the bootstrapper and paket were executables by using chmod.

chmod a+x .paket/paket.bootstrapper.exe
chmod a+x .paket/paket.exe
.paket/paket.exe update

At this point I tried my first compile but got a series of errors rooted at the Store.fs. This is the file containing the SqlDataProvider connection string, and in order for F# to compile it needed to be able to connect to that database. This required the connection string to change to reference the IP address of the VirtualBox host machine, and to replace Trusted_Connection=true with User Id=...;Password=.... The host machine needed the above SQL login created and given dbo rights to the AssetManager database. It also needed a firewall exclusion added for SQL Server.

With those changes in place, the following command performed a successful compile:

xbuild AmApi/AmApi.fsproj

To run it, the executable needed execute rights, then could be called:

cd AmApi/bin/Debug/
chmod a+x AmApi.exe

The integration tests have been hosted in Postman, a Chrome extension, so it was a simple matter to install that extension in Chrome in Ubuntu and open the test collection and run it. The results: 22/22 passed.

Playing in the environment

Beyond this I also tried to get debugging going using VS Code with Ionide. I found some information about possible configuration steps necessary for F# debugging, but couldn’t get it working myself.

I also decided to create a FAKE build by creating an empty project using the Ionide FAKE plugin in VS Code. This created the necessary build.* files which were copied into the project repository, and a paket dependency for FAKE created. The outcome of that can be seen here.


Moving to Suave meant a new logger was required as the original logger used the .NET Core LoggerFactory. Generally for logging I’ve used log4net or flat files. In this case I decided to try using the System.Diagnostics.Trace tools – a little old fashioned perhaps – but supported in .NET 4.6.1 as well as .NET Core (future-proofing!).

Creating a trace involves two parts:
1. Creating a TraceSource instance and calling methods on it;
2. Adding listeners to the config file

In this case it is configured to write warnings and higher to the console, and everything to a file log (AmApi.log).

    <trace autoflush="true" />
      <source name="Log" switchValue="All" switchType="System.Diagnostics.SourceSwitch">
          <add name="console" type="System.Diagnostics.ConsoleTraceListener">
            <filter type="System.Diagnostics.EventTypeFilter" initializeData="Warning"/>
          <add name="logToFileListener"/>
          <remove name="Default"/>
      <add name="logToFileListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="AmApi.log" />     

Suave has built in logging capabilities, such as the colored text displayed in the console. It allows these logs to be accessed by creating a logging adapter and configuring it to be used. This is described here, although the interface definition is more advanced than given on that page, as illustrated by the adapter shown below. This implementation calls a method, SuaveLog, on the main logger class that understands and converts Suave log levels to Diagnostics.TraceEventType.

type SuaveLoggerAdapter() =
    let _log (msg:Suave.Logging.Message) = 
        use strWriter = new System.IO.StringWriter()
        let txt = Suave.Logging.TextWriterTarget(Suave.Logging.LogLevel.Verbose, strWriter) :> Suave.Logging.Logger
        txt.logSimple msg
        Logger.SuaveLog (strWriter.ToString()) msg.level

    interface Suave.Logging.Logger with
        member __.logSimple msg = _log msg
        member __.log level msgFactory = _log (msgFactory level)
        member __.logWithAck level msgFactory = async { do _log (msgFactory level) }

Configuration is done in the startWebServer method. I wanted to preserve the existing logging capabilities, particularly the console, so a CombiningTarget was used. CombiningTarget sends the log messages to multiple loggers.

let defaultLog = Suave.Logging.Targets.create Suave.Logging.LogLevel.Info
let logger = Suave.Logging.CombiningTarget([ defaultLog; Util.SuaveLoggerAdapter() ])
let config = { defaultConfig with logger = logger }
startWebServer config handleRequest

To complete the picture the logging class and instance are shown here. I’ve been lazy and used the underscore here to denote the intention to keep the class private. Alternatively an interface could have been created and a private class defined to implement it. A singleton was also considered but one never knows when it might be useful to split logs so I try to avoid that approach.

type _Logger() = 
    let log = new System.Diagnostics.TraceSource("Log")

    let _log (eventType:Diagnostics.TraceEventType) (msg:string) =
        log.TraceEvent(eventType, 0, (sprintf "%s: %s" (DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff K")) msg))

    override this.Finalize() = 

    member this.Info msg = _log Diagnostics.TraceEventType.Information msg
    member this.Warn msg = _log Diagnostics.TraceEventType.Warning msg
    member this.Error msg = _log Diagnostics.TraceEventType.Error msg

    member this.SuaveLog msg (level:Suave.Logging.LogLevel) = 
        let traceEventType = match level with
                                | Suave.Logging.LogLevel.Verbose -> Diagnostics.TraceEventType.Verbose
                                | Suave.Logging.LogLevel.Debug   -> Diagnostics.TraceEventType.Verbose
                                | Suave.Logging.LogLevel.Info    -> Diagnostics.TraceEventType.Information
                                | Suave.Logging.LogLevel.Warn    -> Diagnostics.TraceEventType.Warning
                                | Suave.Logging.LogLevel.Error   -> Diagnostics.TraceEventType.Error
                                | Suave.Logging.LogLevel.Fatal   -> Diagnostics.TraceEventType.Critical
        _log traceEventType msg

let Logger = _Logger()

Suave Gotcha

I had quite the frustrating hour with Suave trying to combine Webparts. In theory it is very simple:

Function1-that-returns-Webpart >=> Function2-that-returns-Webpart

In practice I kept getting an error “Expecting a type supporting the operator ‘>=>’ but given a function type. You may be missing an argument to a function” when trying to run this (thinned out) code:

let getTemplate : Webpart =
    OK "..." 
    >=> Writers.setMimeType "application/json; charset=utf-8"

let route = choose [ pathScan Path.Assets.templateById getTemplate ]
startWebServer config route

The problem – a missing open Suave.Operators – and without it F# didn’t know what >=> was. I guess it was trying to treat >=> as an inline function, but how it goes from there to that error message presently baffles me.


A Change of Direction

I’ve decided to step away from ASP.NET Core for the moment. I’d like to learn more about F# and good functional practice, and from what I’ve learned so far I feel this would be better achieved via tools and frameworks that were designed for F#. Stepping back also allows use of the .NET Framework and therefore my very much missed debugger.

Choosing a Web Framework

In looking at the options for a web framework for F#, two options stood out as being mature and well-supported: WebSharper; and Suave.IO. My choice is to use Suave.IO because I’m building an API and so am not in need of all the client capabilities that WebSharper seems to be strong in. To that end I’ve been through (i.e. typed out) the Suave Music Store tutorial and read through the documentation.

Picking up a new framework is never easy, and less so when the paradigm being used is new. To aid with that I’ve got the Suave source code from github so I can debug into functions to understand what is going on. There were a few problems referencing the linked files (e.g. Utils/Facade.fs) when building it, which seemed to mysteriously evaporate when the project was reopened. So I’m finally at the point where I can ‘port’ my existing code over the Suave.IO and see what happens. This is where it is at so far, but I hope to report more progress in a day or two:

let webPart =
    choose [
        path Path.Assets.template >=> choose [
                PUT >=> OK "Template PUT"
        pathScan Path.Assets.templateById (fun guid -> OK (sprintf "Get Template by Id: %s" guid))

        path Path.Assets.template >=> choose [
                PUT >=> OK "Asset PUT"
        pathScan Path.Assets.assetById (fun guid -> OK (sprintf "Get Asset by Id: %s" guid))
        NOT_FOUND "No handler found"

let main argv = 
    printfn "%A" argv

    let config = { defaultConfig with bindings = [ { scheme = HTTP; socketBinding = { ip = Net.IPAddress.Parse(""); port = 5000us }} ]}

    startWebServer config webPart
    0 // return an integer exit code