F# Web Services on any platform in and out of a web server!

September 28th, 2011 by mythz Leave a reply »

Following on from my previous post where I took a first look at F# through my C# tinted eyes, I looked into some of the advantages of what this versatile language brings to a C# devs table. One of the major benefits I mentioned in passing but failed to explain in detail was it’s exceptionally good async story, which in many respects provides arguably the best async programming development experience to date on any platform.

F# and .NET Web Services

If F# only had to interface with other code as its inputs and outputs, the async world of F# is pristine and beautiful. Such is rarely the case so we’re stuck with having to interface with existing frameworks to provide these additional user facing services. Unfortunately the Web Services story for .NET isn’t pretty, where if for whatever reason you’re forced to use Microsoft-only technologies, you’re left with either having to deal with the WCF problem or extend MVC’s framework and roll your own REST-ful framework-in-a-framework yourself – which although less capable, I’ve witnessed to be a viable alternative providing a better iterative experience than WCF in the wild. Another web framework worth considering along similar lines, but developed in true Open Source spirit is NancyFX.

However if like me you like Web Services and still want to use a framework optimized for the task but consider WCF to be an anti-pattern promoting, over architected abstraction I’m happy to highlight a more elegant option in Service Stack which does the same job as WCF in allowing you to expose XML, JSON and SOAP services (as well as CSV, JSV & HTML formats) but does so cleanly, out-of-the-box, without any configuration required! It’s typed, DTO-first development model gets out of your way providing a friction-free dev experience that encourages the development of clean, best-practice web services – easily consumable from any client.

I should note the latest Web Service offering coming out of Redmond: WCF Web API is not be confused with WCF (even if the naming tries) does a much better job of ‘exposing HTTP and REST’ rather than hiding it like the original WCF framework upon which it is built. This may work better for you, although my preference for Open source solutions favouring light, DRY, typed, performance-focused API’s with the ability to run cross platform keeps me using and continue to recommend and maintain Service Stack for the foreseeable future.

Hello, F# World!

To get started we just need the Service Stack dlls that can be downloaded from GitHub. In the unzipped folder you can spark up your favourite text editor and write your first Hello, World web service which looks like [gist]:

open System
open ServiceStack.ServiceHost
open ServiceStack.WebHost.Endpoints

type Hello = { mutable Name: string; }
type HelloResponse = { mutable Result: string; }
type HelloService() =
    interface IService<Hello> with
        member this.Execute (req:Hello) = { Result = "Hello, " + req.Name } :> Object

//Define the Web Services AppHost
type AppHost =
    inherit AppHostHttpListenerBase
    new() = { inherit AppHostHttpListenerBase("Hello F# Services", typeof<HelloService>.Assembly) }
    override this.Configure container =
        base.Routes
            .Add<Hello>("/hello")
            .Add<Hello>("/hello/{Name}") |> ignore

//Run it!
[<EntryPoint>]
let main args =
    let host = if args.Length = 0 then "http://*:8080/" else args.[0]
    printfn "listening on %s ..." host
    let appHost = new AppHost()
    appHost.Init()
    appHost.Start host
    Console.ReadLine() |> ignore
    0

The rest of the code except for the 5 lines of code needed to create the actual service need only be written once which is just used to setup the AppHost and run it, in this case as a Console Application.

Great, once you copy all that in, and hit save using the filename Hello.fs – you can compile with the 1-liner:

fsharpc -r:ServiceStack.Common.dll -r:ServiceStack.Interfaces.dll -r:ServiceStack.Text.dll -r:ServiceStack.dll Hello.fs

Which cuts you a nice Hello.exe that you can double-click to run on Windows, otherwise run on OSX or Linux with:

sudo mono Hello.exe

And Voila! your stand alone F# self-hosting Web Service is ready to serve you at: http://localhost:8080/hello/FSharp!

Convert into an ASP.NET Web Service

To convert this into an ASP.NET application we just need to do some minor tweaks add the appropriate files to deal with the nuances of having an ASP.NET application. For this we need to venture back to a time before VS.NET templates existed that did all this for us.
Note: All files including HelloAsp.fs, Global.asax and Web.Config files used in the walkthrough below are available on this [gist].

First lets take a copy of the file and call it HelloAsp.fs

1. As we want to create a .NET assembly we wrap the entire script in a namespace adding the declaration on top and indenting the rest of the file

namespace HelloFSharp

2. Change the AppHost from a Http Listener to an ASP.NET AppHost by removing the word HttpListener from AppHostHttpListenerBase e.g:

    type AppHost =
        inherit AppHostBase
        new() = { inherit AppHostBase("Hello F# Services", typeof<HelloService>.Assembly) }
        override this.Configure container =
            base.Routes
                .Add<Hello>("/hello")
                .Add<Hello>("/hello/{Name}") |> ignore

3. Replace starting the AppHost from the command line with initialising it from HttpApplication Application_Start() event, i.e:

    type Global =
        inherit System.Web.HttpApplication
        new() = { }
        member x.Application_Start() =
            let appHost = new AppHost()
            appHost.Init()

4. Create the Global.asax stub to point it to the Global type, i.e:

echo "<%@ Application Inherits="HelloFSharp.Global" %>" >> Global.asax

5. Compile HelloAsp.fs into a library since its now an ASP.NET app instead of a stand-alone executable:

fsharpc -r:ServiceStack.Common.dll -r:ServiceStack.Interfaces.dll -r:ServiceStack.Text.dll -r:ServiceStack.dll --target:library HelloAsp.fs

6. make a bin directory and copy all the dlls into it:

mkdir bin && cp *.dll bin

7. Copy the desired Web.config mapping from Hello World Tutorial

<?xml version="1.0"?>
<configuration>
<system.web>
  <httpHandlers>
    <add path="*" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*"/>
  </httpHandlers>
</system.web>
<!-- Required for IIS 7.0 -->
<system.webServer>
  <handlers>
    <add path="*" name="ServiceStack.Factory" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" preCondition="integratedMode" resourceType="Unspecified" allowPathInfo="true" />
  </handlers>
</system.webServer>
</configuration>

8. Run the .NET 4.0 version of xsp in the current directory

xsp4

If all went well you should see the following output:

Listening on address: 0.0.0.0
Root directory: /Users/mythz/src/fsharp/fsharpstack
Listening on port: 8080 (non-secure)
Hit Return to stop the server.

and you’ll be able to hit the service again using the same url at http://localhost:8080/hello/FSharp!

You now have a fully-fledged ServiceStack ASP.NET application that can be hosted in any ASP.NET compatible web server e.g:

  • IIS
  • Apache + mod_mono
  • Nginx + MonoFastCGI
  • XSP
  • WebDevServer.exe

Now that you know how to create functional F# web services, you can read more about the goodies you get for free when using Service Stack, complete with live links to all those juicy XML, JSON, SOAP, HTML, CSV and JSV Formats check out: http://www.servicestack.net/ServiceStack.Hello/

Next – Async Goodness!

With the basics out of the way tomorrow we’ll tackle a more complex service taking advantage of F#’s async and parallel good ness to provide nice high-level aggregate features off twitters public API.

Stay Tuned!

Advertisement