comment
More and more .NET developers come to appreciate functional programming, and this is really good news for F#. A couple weeks ago Scott Hanselman ran a short article on running Suave.io apps as Azure web apps deployed via GitHub. His setup was the following:
- You configure your Azure web app to be sourced from a GitHub repository. This sets up a GitHub hook that notifies Azure on every commit.
- Your suave.io app consists of an F# script (
site\webserver.fsx
) inside an empty ASP.NET project with aweb.config
. - On a commit, Azure executes a deployment script (
deploy.cmd
via.deployment
) found in your project. - This script uses Paket to restore FAKE and Suave, and uses FAKE to execute an F# script (
build.fsx
) by passing it tofsi.exe
shipped with FAKE. - This FAKE script can optionally execute various build tasks, if necessary, to build a site - in Scott's example it was just used as a placeholder script.
- Finally, the web app is copied to the right folder in your Azure web app.
- When starting, the app executes a "setup" step, configured as an
<httpPlatform>
directive. This in turn uses FAKE to executesite\webserver.fsx
, which starts Suave.io and listens on a given port that is then mapped to the standard HTTP port.
This sequence is more complicated than it needs to be because it has to work around the lack of the F# tools and core libraries when setting up a new Azure web app deployment. Since Scott's article, I filed a ticket to bundle the F# compiler and tools in a Nuget, and thanks to Don Syme and Steffen Forkmann, that Nuget was out within a couple days.
Armed with that, we quickly put together a similar deployment setup for WebSharper client-server apps (other types of WebSharper apps are equally possible.) This has the obvious advantage that:
- It uses WebSharper, so you can add client-side (e.g. JavaScript) functionality as well and write it in F#.
- It produces an ASP.NET app that serves fine in Azure without the need to run a separate server process like Suave.io (although you can also create OWIN-based self-hosted WebSharper applications and run them as in Scott's scenario.)
- It no longer needs FAKE to compile F# apps or run F# scripts.
Loic blogged the technical details in his WebSharper: From Zero to an Azure-deployed Web Application article, using a WebSharper implementation/clone of the "2048" game. I also put together a simpler template that you can use for client-server applications, and it's available in...
this GitHub repository
The template uses Paket instead of Nuget, and you can build your project with build.cmd
(you will need curl installed and on your path). Run build.cmd
before opening in Visual Studio as well.
You can also get started quickly by clicking here:
There is a single main.fs
file, and it contains both the server and the client functionality:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
namespace MyApplication open WebSharper open WebSharper.Sitelets type Action = | [<CompiledName "">] Home | [<CompiledName "about">] About module Server = [<Rpc>] let DoSomething input = let R (s: string) = System.String(List.ofSeq s |> List.rev |> Array.ofList) async { return R input } [<JavaScript>] module Client = open WebSharper.Html.Client let Main () = let input = Input [Attr.Value ""] let output = H1 [] Div [ input Button [Text "Send"] |>! OnClick (fun _ _ -> async { let! data = Server.DoSomething input.Value output.Text <- data } |> Async.Start ) HR [] H4 [Class "text-muted"] -- Text "The server responded:" Div [Class "jumbotron"] -< [output] ] open WebSharper.Html.Server module Skin = open System.Web type Page = { Title : string Menubar : Element list Body : Element list } let MainTemplate = Content.Template<Page>("~/Main.html") .With("title", fun x -> x.Title) .With("menubar", fun x -> x.Menubar) .With("body", fun x -> x.Body) let Menubar (ctx: Context<Action>) action = let ( => ) text act = LI [if action = act then yield Class "active"] -< [ A [HRef (ctx.Link act)] -< [Text text] ] [ LI ["Home" => Action.Home] LI ["About" => Action.About] ] let WithTemplate action title body : Content<Action> = Content.WithTemplate MainTemplate <| fun ctx -> { Title = title Menubar = Menubar ctx action Body = body ctx } module Site = module Pages = let Home = Skin.WithTemplate Action.Home "Home" <| fun ctx -> [ H1 [Text "Say Hi to Azure"] Div [ClientSide <@ Client.Main() @>] ] let About = Skin.WithTemplate Action.About "About" <| fun ctx -> [ H1 [Text "About"] P [Text "This is a template WebSharper client-server application that you can easily deploy to Azure from source control."] ] let Main = Sitelet.Infer (function | Action.Home -> Pages.Home | Action.About -> Pages.About ) [<Sealed>] type Website() = interface IWebsite<Action> with member this.Sitelet = Site.Main member this.Actions = [Action.Home; Action.About] [<assembly: Website(typeof<Website>)>] do ()
This uses basic WebSharper templating and a master main.html
template and implements a two page sitelet application:

You can run it directly here.
Happy coding!