By Loïc Denuzière on Wednesday, July 22, 2015 — 5 comments

WebSharper 3.3 released with client-side JSON serialization Core team

We are happy to announce the availability of WebSharper 3.3, which you can download here. The main highlight of this release is the addition of JSON serialization functions for client-side code.

The format used for this serialization is identical to the format used by inferred Sitelets. This means that you can now easily craft your request data on the client, perform an AJAX call to your Sitelets API, and parse the reply, all of this type-safely!

For example, for a website defined as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
open WebSharper
open WebSharper.Sitelets

type EndPoints =
    | [<EndPoint "POST /article"; Json "article">]
      PostArticle of article: Article
and Article = { title: string; body: string }

[<Website>]
let app = Sitelet.Infer <| function
    | PostArticle article ->
        let articleId = ApplicationLogic.SaveArticle article
        Content.JsonContent (fun _ -> articleId)

You can invoke the REST endpoint POST /article from the client-side like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[<JavaScript>]
module Client =
    open WebSharper.JavaScript
    open WebSharper.JQuery

    /// General function to send an AJAX request with a body.
    let Ajax (method: string) (url: string) (serializedData: string) : Async<string> =
        Async.FromContinuations <| fun (ok, ko, _) ->
            JQuery.Ajax(
                JQuery.AjaxSettings(
                    Url = url,
                    Type = As<JQuery.RequestType> method,
                    ContentType = "application/json",
                    DataType = JQuery.DataType.Text,
                    Data = serializedData,
                    Success = (fun (result, _, _) -> ok (result :?> string)),
                    Error = (fun (jqXHR, _, _) -> ko (System.Exception(jqXHR.ResponseText)))))
            |> ignore

    /// Use Json.Serialize and Deserialize to send and receive data to and from the server.
    let PostBlogArticle (article: Article) : Async<int> =
        async { let! response = Ajax "POST" "/article" (Json.Serialize article)
                return Json.Deserialize<int> response }

This new API is located in the module WebSharper.Json. Its only limitation compared with Sitelets is that the [<DateTimeFormat>] attribute is currently ignored, as JavaScript doesn't have built-in datetime formatting capabilities. We might consider using an external library such as moment.js for this purpose in the future.

Future plans

We have lots of exciting things to come in WebSharper. Here is what you can expect from upcoming releases:

  • F# 4.0 support, including JavaScript proxies for the new collection library functions.
  • A new, cleaner HTML combinator syntax. This syntax will supersede the current Html.Server, Html.Client and UI.Next.HTML with a unique type. This means that the same HTML code will be usable both from the server and client side.

Happy coding!

By Loïc Denuzière on Tuesday, July 14, 2015 — 0 comments

WebSharper 3.2.22 released Core team

This new WebSharper version is a bugfix release. The main fixes concern dynamic compilation to JavaScript, which includes Warp applications.

Change log:

  • More verbose error message when failing to compile a function to JavaScript.
  • Fix dynamic compilation to JavaScript of generic methods on generic types.
  • Fix #444: dynamic compilation to JavaScript of union type field access.
  • Fix various proxies whose types didn't exactly match with the original function, and were accepted by standard compilation but not by dynamic compilation.
  • Make TypeScript declaration output optional in FrontEnd.
  • Fix #445: equality and comparison on arbitrary objects.
  • Fix Runtime.Inherit for when the parent class isn't included in dependencies.
  • Fix [<Website>] not recognized on Sitelet values.

Happy coding!

By András Jankó on Thursday, June 25, 2015 — 0 comments

WebSharper 3.2.10 released Core team

This release fixes some bugs when compiling from F# quotations (used for example by WebSharper.Warp).

Full change log since 3.2.7:

  • #430: Inferred sitelets: Allow specifying the method in EndPoint

    For example this:

    1
    2
    
    type Action =
    | [<EndPoint "GET /home">] Home

    would be equivalent to:

    1
    2
    
    type Action =
    | [<Method "GET"; EndPoint "/home">] Home
  • #431: Don't write meta and init script tags when there are no resources

  • #437: Interfaces generated by WIG

    Previously using interfaces generated invalid IL, implementations were missing. Also interface methods had no Inline attributes for WebSharper translation.

    Now an interface is auto-implemented on the class. Inlines are copied from the interface declaration, no customization is possible currently. If there are multiple interfaces defining the same method, the inline found on the first interface definition will be used.

  • #435: Generic type constructor in tranlating a quoatation

  • #424: Nested types are handled incorrectly when translating with runtime reflection
By Adam Granicz on Monday, June 15, 2015 — 8 comments

Introducing WebSharper Warp Core team

WebSharper Warp is a friction-less web development library for building scripted and standalone full-stack F# client-server applications. Warp is built on top of WebSharper and is designed to help you become more productive and benefit from the rich WebSharper features more quickly and more directly. While Warp shorthands target the most typical applications (text, SPAs, multi-page) and easy exploration, you can extend your Warp applications with the full WebSharper capabilities at any time.

Installing

To get started with Warp is super-easy, all you need is to open a new F# Console Application (or any other F# project type if you want to script applications), and add WebSharper.Warp to it:

1
Install-Package WebSharper.Warp

Or if you use Paket:

1
2
paket init
paket add nuget WebSharper.Warp

Hello world!

The simplest Warp site just serves text and consist of a single endpoint (/), by default listening on http://localhost:9000.

1
2
3
4
5
6
open WebSharper

let MyApp = Warp.Text "Hello world!"

[<EntryPoint>]
do Warp.RunAndWaitForInput(MyApp) |> ignore

Single Page Applications

While serving text is fun and often useful, going beyond isn't any complicated. Warp also helps constructing HTML. In the most basic form, you can create single page applications (SPAs) using Warp.CreateSPA and WebSharper's server-side HTML combinators:

1
2
3
4
5
6
7
8
open WebSharper.Html.Server

let MySite =
    Warp.CreateSPA (fun ctx ->
        [H1 [Text "Hello world!"]])

[<EntryPoint>]
do Warp.RunAndWaitForInput(MySite) |> ignore

Multi-page applications

Using multiple EndPoints and Warp.CreateApplication, you can define multi-page Warp applications. When constructing the actual pages, Warp.Page comes handy - allowing you to fill the Title, Head, and the Body parts on demand. Warp.Page pages are fully autonomous and will automatically contain the dependencies of any client-side code used on the page.

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
type Endpoints =
    | [<EndPoint "GET /">] Home
    | [<EndPoint "GET /about">] About

let MySite =
    Warp.CreateApplication (fun ctx endpoint ->
        let (=>) label endpoint = A [HRef (ctx.Link endpoint)] -< [Text label]
        match endpoint with
        | Endpoints.Home ->
            Warp.Page(
                Body =
                    [
                        H1 [Text "Hello world!"]
                        "About" => Endpoints.About
                    ]
            )
        | Endpoints.About ->
            Warp.Page(
                Body =
                    [
                        P [Text "This is a simple app"]
                        "Home" => Endpoints.Home
                    ]
            )
    )

[<EntryPoint>]
do Warp.RunAndWaitForInput(MySite) |> ignore

Adding client-side functionality

Warp applications can easily incorporate client-side content and functionality, giving an absolute edge over any web development library. The example below is reimplemented from Deploying WebSharper apps to Azure via GitHub, and although it omits the more advanced templating in that approach (which is straightforward to add to this implementation), it greatly simplifies constructing and running the application.

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
module Server =
    [<Server>]
    let DoWork (s: string) = 
        async {
            return System.String(List.ofSeq s |> List.rev |> Array.ofList)
        }

[<Client>]
module Client =
    open WebSharper.JavaScript
    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.DoWork input.Value
                        output.Text <- data
                    }
                    |> Async.Start
                )
            HR []
            H4 [Class "text-muted"] -- Text "The server responded:"
            Div [Class "jumbotron"] -< [output]
        ]

let MySite =
    Warp.CreateSPA (fun ctx ->
        [
            H1 [Text "Say Hi to the server"]
            Div [ClientSide <@ Client.Main() @>]
        ])

[<EntryPoint>]
do Warp.RunAndWaitForInput(MySite) |> ignore

Taking things further

Creating RESTful applications, using client-side visualizations is just as easy. For a quick example, here is a Chart.js-based visualization using the WebSharper.ChartJs WebSharper extension:

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
[<Client>]
module Client =
    open WebSharper.JavaScript
    open WebSharper.Html.Client
    open WebSharper.ChartJs

    let RadarChart () =
        Div [
            H3 [Text "Activity Chart"]
            Canvas [Attr.Width  "450"; Attr.Height "300"]
            |>! OnAfterRender (fun canvas ->
                let canvas = As<CanvasElement> canvas.Dom
                RadarChartData(
                    Labels   = [| "Eating"; "Drinking"; "Sleeping";
                                  "Designing"; "Coding"; "Cycling"; "Running" |],
                    Datasets = [|
                        RadarChartDataset(
                            FillColor   = "rgba(151, 187, 205, 0.2)",
                            StrokeColor = "rgba(151, 187, 205, 1)",
                            PointColor  = "rgba(151, 187, 205, 1)",
                            Data        = [|28.0; 48.0; 40.0; 19.0; 96.0; 27.0; 100.0|]
                        )
                        RadarChartDataset(
                            FillColor   = "rgba(220, 220, 220, 0.2)",
                            StrokeColor = "rgba(220, 220, 220, 1)",
                            PointColor  = "rgba(220,220,220,1)",
                            Data        = [|65.0; 59.0; 90.0; 81.0; 56.0; 55.0; 40.0|]
                        )
                    |]
                )
                |> Chart(canvas.GetContext "2d").Radar
                |> ignore
            )
        ]

let MySite =
    Warp.CreateSPA (fun ctx ->
        [
            H1 [Text "Charts are easy with WebSharper Warp!"]
            Div [ClientSide <@ Client.RadarChart() @>]
        ])

[<EntryPoint>]
do Warp.RunAndWaitForInput(MySite) |> ignore

Scripting with Warp

When you add the WebSharper.Warp NuGet package to your project in Visual Studio, a new document tab will open giving the necessary boilerplate for using Warp in scripted applications.

For instance, the SPA example above can be written as an F# script and executed in F# Interative:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#I "../packages/Owin.1.0/lib/net40"
#I "../packages/Microsoft.Owin.3.0.1/lib/net45"
#I "../packages/Microsoft.Owin.Host.HttpListener.3.0.1/lib/net45"
#I "../packages/Microsoft.Owin.Hosting.3.0.1/lib/net45"
#I "../packages/Microsoft.Owin.FileSystems.3.0.1/lib/net45"
#I "../packages/Microsoft.Owin.StaticFiles.3.0.1/lib/net45"
#I "../packages/WebSharper.3.2.8.170/lib/net40"
#I "../packages/WebSharper.Compiler.3.2.4.170/lib/net40"
#I "../packages/WebSharper.Owin.3.2.6.83/lib/net45"
#load "../packages/WebSharper.Warp.3.2.10.13/tools/reference.fsx"

open WebSharper
open WebSharper.Html.Server

let MySite =
    Warp.CreateSPA (fun ctx ->
        [H1 [Text "Hello world!"]])

do Warp.RunAndWaitForInput(MySite) |> ignore

If you use Paket, then you should replace the #-lines above with this one:

1
#load "../packages/WebSharper.Warp/tools/reference-nover.fsx"

In FSI, you should see:

1
2
3
4
5
6
7
8
--> Added 'c:\sandbox\test\Library1\HelloWorld\../packages/Owin.1.0/lib/net40' to library include path
[... more lines ...]

[Loading c:\sandbox\test\Library1\packages\WebSharper.Warp.3.2.10.13\tools\reference.fsx]

namespace FSI_0004

Serving http://localhost:9000/, press Enter to stop.

You can then test this application as before:

Getting help

Warp now has a chat room where you can ask questions, feel free to drop by:

Happy coding!

By Adam Granicz on Tuesday, June 9, 2015 — 1 comment

WebSharper 3.2 with support for scriptable applications, better resource management, and additional streamlined syntax Core team

We are thrilled to announce the availability of WebSharper 3.2, paving the road to further upcoming enhancements to streamline developing and deploying WebSharper apps, and also shipping several key changes summarized here.

No need to annotate sitelet assemblies with Website

This is what pre-3.2 code looked like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module Site =
    ...
    let Main =
        Sitelet.Sum [
            Sitelet.Content "/" Home HomePage
            Sitelet.Content "/About" About AboutPage
        ]

[<Sealed>]
type Website() =
    interface IWebsite<Action> with
        member this.Sitelet = Site.Main
        member this.Actions = []

[<assembly: Website(typeof<Website>)>]
do ()

Now you can simply do:

1
2
3
4
5
6
7
8
module Site =
    ...
    [<Website>]
    let Main =
        Sitelet.Sum [
            Sitelet.Content "/" Home HomePage
            Sitelet.Content "/About" About AboutPage
        ]

Old code works as before, but we now look for the Website attribute on values as well if no assembly-level instance is found, yielding the shorter syntax above.

Dot-syntax for chained event handlers

The following code:

1
2
3
4
Button [Text "some text"]
|>! OnClick (fun e args ->
    JS.Alert "Clicked"
)

can now be written as:

1
2
3
4
Button([Text "some text"])
    .OnClick(fun e args ->
        JS.Alert "Clicked"
    )

This syntax is more familiar to many developers, eliminates the need for a special operator (|>!), and makes code more discoverable by having API comments and code completion choices available when attaching the event handler.

Server-side templating enhancements

Traditionally, in sitelet templates you had the following line in the <HEAD> section to stand for the placeholder for including generated page dependencies (e.g. all the CSS, JS, etc. files that are implicitly referenced in your page):

1
<meta name="generator" content="websharper" data-replace="scripts" />

With 3.2, you can now refine how these dependencies are inserted if you provide additional placeholders:

  1. styles: output the generated stylesheets only. Usually, you will want to put this placeholder in the <HEAD> section.
  2. meta: output the client-server integration (arguments to server-side controls, etc.) bits only. You will want this in <HEAD>

When either of these are present, scripts only outputs the JavaScript dependencies, making it possible to place this placeholder anywhere else, away from the other bits, say, to the tail of the <BODY> element.

A typical new template might thus be:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta data-replace="meta" />
    <meta data-replace="styles" />
    ...
</head>
<body>
  ...
  <script data-replace="scripts"></script>
</body>
</html>

Change log

The full list of items completed since the last 3.1.6 release:

  • #410: add FuncWithOnlyThis type, compile error on invalid use of FuncWithThis
  • #394: JQuery.Add(JQuery) binding missing
  • #411: ref cells are broken
  • #412: Sequence range throws an exception when end < start
  • #413: Range Expressions Are Not Properly Compiled
  • #415: Missing proxy for Seq.last
  • #417: ClientSide doesn't incur a dependency on the declaring type of the invoked method
  • #418: Json: record in single union case field doesn't respect [<Name>] for its fields
  • #421: Sitelet templates: intermittent IOException on changed file
  • #419: Allow splitting generated styles and scripts via separate placeholders
  • #422: Allow defining a sitelet assembly by just putting [<Website>] on a Sitelet<'T> value
  • #423: Html.Client: Add chainable extension methods for event handlers
  • #425: Seq.distinct/distinctBy proxy only compares hashes
  • #426: Create a WebSharper.Compiler nuget package
  • #414: sprintf Is Not Properly Compiled
  • #429: Add WebSharperProject=Ignore build task option
  • #428: Sitelet.Infer: add EndPointAttribute as synonym for CompiledNameAttribute
  • #427: Sitelet.Infer: allow prefixing union case's CompiledName with /

Just a note: CloudSharper out-of-the-box templates still use 3.1 - we will be migrating these to 3.2 in the following days, keep an eye on our blog for when this is finalized.

Happy coding!

By Loïc Denuzière on Saturday, May 23, 2015 — 0 comments

WebSharper 3.1 published Core team

It's barely been a month since we released WebSharper 3.0, and we are now at it again with the release of WebSharper 3.1. Without further ado, here are the main highlights.

ASP.NET MVC support

WebSharper has supported including client-side controls in ASPX pages since version 1.0, and running sitelets alongside ASP.NET since version 2.0. With version 3.1 and WebSharper.AspNetMvc, WebSharper now has extended support for running together with ASP.NET MVC in the following scenarios:

  • Including WebSharper client-side controls in pages that use the Razor view engine. Here is an example:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    
    @{
        // Create a web control
        var myControl = WebSharper.AspNetMvc.ScriptManager.Register(new MyWebSharperControl())
    }
    <!DOCTYPE html>
    <html>
      <head>
        <title>Testing WebSharper with ASP.NET MVC!</title>
        <!-- Render the needed css and script tags -->
        @WebSharper.AspNetMvc.ScriptManager.Head()
      </head>
      <body>
        <h1>Here is my control:</h1>
        <!-- Render the control -->
        @myControl
      </body>
    </html>

    Remoting is also supported, you can simply call server-side [<Rpc>]-annotated functions from MyWebSharperControl.

  • Running WebSharper sitelets alongside ASP.NET MVC, serving pages and APIs from both. You can decide which one takes priority when their URL spaces overlap.

See the WebSharper ASP.NET documentation page to learn how to integrate WebSharper.AspNetMvc into an ASP.NET MVC application.

Lightweight syntax to embed client-side elements in sitelets markup

Until now, in order to include client-side generated markup (whether using Html.Client or UI.Next) inside Html.Server markup, you had to create a new class inheriting from Web.Control and override its Body property. There is now a much easier syntax that you can use thanks to the ClientSide function:

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
[<JavaScript>]
module Client =
    open WebSharper.Html.Client

    let myContent text1 text2 = I [Text (text1 + "; " + text2)]

module Server =
    open WebSharper.Html.Server
    
    // Old Web.Control style:

    type MyControl(text1, text2) =
        inherit Web.Control()
        [<JavaScript>]
        override this.Body = Client.myContent text1 text2 :> _
        
    let OldBody =
        let t = "a local variable"
        Div [ new MyControl(t, "a literal") ]

    // New ClientSide style:

    let Body =
        let t = "a local variable"
        Div [ ClientSide <@ Client.myContent t "a literal" @> ]

Unlike the presence of a quotation suggests, this doesn't run any F#-to-JavaScript compilation at runtime. The quotation is only here to allow looking up the fully qualified name of the function you are calling (Client.myContent in the above example) and inlining it in the resulting page, alongside its JSON-serialized arguments.

You can read more about ClientSide in the documentation.

Sitelets routing enhancements

WebSharper 3.1 includes several enhancements to sitelets routing.

Wildcard paths

You can add the [<Wildcard>] attribute to an action union case to make its last argument match the remainder of the path. This argument must be of type list, array, or string.

1
2
3
4
5
6
7
8
type Action =
    | [<Wildcard>] Articles of pageId: int * tags: list<string>
    | [<Wildcard>] Articles2 of tags: string[]
    | [<Wildcard>] GetFile of path: string

// GET /Articles/12/fsharp/websharper   -->   Articles(12, ["fsharp";"websharper"])
// GET /Articles2                       -->   Articles2 [||]
// Get /GetFile/Content/css/main.css    -->   GetFile "Content/css/main.css"

Multiple actions with the same prefix

You can now create an action with several cases that parse the same prefix (ie. have the same [<CompiledName>]) on the same method. They will be tried in the order in which they are declared, until one of them matches. This is very convenient for REST-style URLs where additional information can be added with additional URL fragments.

1
2
3
4
5
6
7
8
type Action =
    | [<Method "GET"; CompiledName "blog">] ListBlogEntries
    | [<Method "GET"; CompiledName "blog">] BlogEntry of id: int
    | [<Method "GET"; CompiledName "blog">] BlogEntryWithSlug of id: int * slug: string

// GET /blog                               -->   ListBlogEntries
// GET /blog/123                           -->   BlogEntry 123
// GET /blog/123/websharper-31-published   -->   BlogEntryWithSlug(12, "websharper-31-published")

Parsing form post data

Web forms using method="post" send their data in the request body with a format determined by enctype (generally either application/x-www-form-urlencoded or multipart/form-data). This data is available in the sitelet context as Request.Post. It is now also possible to directly parse it in the action using [<FormData>]. This attribute is used in a similar way as [<Query>].

1
2
3
4
5
6
7
8
type Action =
    | [<Method "POST"; FormData("firstName","lastName")>]
        Register of firstName: string; lastName: string

// POST /Register
// Content-Type: application/x-www-form-urlencoded
//
// firstName=Loic&lastName=Denuziere                 --> Register("Loic", "Denuziere")

Disposable enumerators

Perviously WebSharper translation didn't dispose enumerator objects used internally in for ... in loops. Also, enumerators created by Seq module functions didn't dispose the wrapped enumerators. These all now follow semantics of their .NET counterparts.

The future

As you can see, we are now committing to a higher turn-around of WebSharper releases. Among enhancements you can expect in the future, we will be adding proxies for the new library functions as soon as F# 4.0 hits the shelves.

We are also preparing a service to try WebSharper F#-to-JavaScript compilation online. You will be able to experiment with F#-based web applications quicker and more easily than ever!

We cannot wait to make this available for you to try. In the meantime, happy coding!

By Loïc Denuzière on Thursday, May 21, 2015 — 0 comments

CloudSharper 0.9.31 published Core team

This release of CloudSharper 0.9.31.0 brings it on par with WebSharper 3.1. CloudSharper itself uses WebSharper 3.1, and the web project templates are also updated to reference WebSharper 3.1.6.

You can of course still use CloudSharper to work on WebSharper 3.0 projects, but we nevertheless recommend that you update your projects to WebSharper 3.1.

Happy coding!

By Adam Granicz on Friday, May 15, 2015 — 1 comment

Deploying WebSharper apps to Azure via GitHub Core team

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:

  1. 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.
  2. Your suave.io app consists of an F# script (site\webserver.fsx) inside an empty ASP.NET project with a web.config.
  3. On a commit, Azure executes a deployment script (deploy.cmd via .deployment) found in your project.
  4. This script uses Paket to restore FAKE and Suave, and uses FAKE to execute an F# script (build.fsx) by passing it to fsi.exe shipped with FAKE.
  5. 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.
  6. Finally, the web app is copied to the right folder in your Azure web app.
  7. When starting, the app executes a "setup" step, configured as an <httpPlatform> directive. This in turn uses FAKE to execute site\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!

By Loïc Denuzière on Tuesday, May 12, 2015 — 0 comments

WebSharper: From Zero to an Azure-deployed Web Application Core team

We are often asked what the deployment story is like for WebSharper applications. Our usual reply has long been that WebSharper applications follow standard formats, in particular:

  • Client-Server Web Applications are simply ASP.NET applications, and can be deployed using usual methods such as publishing from Visual Studio or using Azure's git integration;
  • HTML Applications are composed of static files located in $(WebSharperHtmlDirectory) (which is bin/html by default) and can be deployed from there using the method of your choice.
  • Single-Page Applications are also composed of static files, index.html and the Content folder, so the same methods apply.

However there can be some caveats, in particular with regards to running the F# compiler and referencing FSharp.Core.dll in build-and-deploy environments.

Fortunately, the recently released NuGet package FSharp.Compiler.Tools combined with the excellent package manager Paket now provide a nice and streamlined development and deployment experience for git-hosted, Azure-deployed applications.

This article presents the build and deployment setup for a reimplementation of the popular game 2048, available on GitHub. To try it out, simply click the button "Deploy to Azure" and follow the instructions.

The project

This particular project was created as a Single-Page Application; this project type was chosen because the application runs on a single page and is only composed of client-side code. The solution, 2048.sln, contains a single project located at Game2048/Game2048.fsproj.

If you want to recreate this setup, you can create a Single-Page Application from Visual Studio or Xamarin Studio / MonoDevelop with the WebSharper extension installed. This deployment setup will also work if you create a Client-Server Application or an HTML Application instead. For Self-Hosted Client-Server Applications, you will additionally need to set up an HttpPlatformHandler to run the generated executable, similarly to Scott Hanselman's Suave setup.

Paket

For package management, the project uses Paket. It offers many advantages over traditional NuGet, which you can read about here.

Note that paket restore is run in the build script before running MSBuild. Indeed, since we will be importing several .targets files that come from packages, the packages must be restored before running MSBuild or opening the project in an IDE. So for your first build after cloning the 2048 project, you can either run the full build.cmd, or if you only want to restore the packages, you can run:

1
.paket/paket.bootstrapper.exe && .paket/paket.exe restore

If you want to reproduce this setup for your own project as created in the previous section, here are the steps:

  • Remove the WebSharper NuGet package from the project and delete the file <your_project_name>/packages.config if it exists.

  • Download paket.bootstrapper.exe and paket.targets from here into the folder .paket.

  • To ensure that you build with the right package versions after a git pull, add the following to <your_project_name>.fsproj:

    1
    
    <Import Project="..\.paket\paket.targets" />
  • Run the following commands:

    1
    2
    3
    4
    5
    6
    
    # Download paket.exe:
    .paket/bootstrapper.exe
    # Initialize paket.dependencies:
    .paket/paket.exe init
    # Install the WebSharper package into your project:
    .paket/paket.exe add nuget WebSharper project <your_project_name>
  • The files paket.dependencies, paket.lock and <your_project_name>/paket.references must be committed.

The F# Compiler

Since fsc is not available on Azure, we retrieve it from NuGet. We reference the package FSharp.Compiler.Tools which contains the compiler toolchain. By importing tools/Microsoft.FSharp.targets from this package in our project file, we instruct MSBuild to use the F# compiler from the package. This means that even when building locally, fsc from the package will be used. This ensures consistency between local and deployment builds.

If you want to apply this change to your own project, here are the steps:

  • Install the F# compiler package:

    1
    
    .paket/paket.exe add nuget FSharp.Compiler.Tools
  • Use it in your project: in <your_project_name>.fsproj:
    • Remove any references to Microsoft.FSharp.targets and FSharp.Core.dll. In a Visual Studio-created project, this means removing this whole block:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      
      <!-- F# targets -->
      <Choose>
        <When Condition="'$(VisualStudioVersion)' == '11.0'">
          <PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')">
            <FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>
          </PropertyGroup>
        </When>
        <Otherwise>
          <PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')">
            <FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>
          </PropertyGroup>
        </Otherwise>
      </Choose>
      <Import Project="$(FSharpTargetsPath)" />
    • and add this line instead:

      1
      
        <Import Project="..\packages\FSharp.Compiler.Tools\tools\Microsoft.FSharp.targets" />

You now have a project that should build and run fine locally. Try it out!

2048 Screenshot

Azure Deployment

Now, on to the deployment setup itself. We will be using a custom build script, so we need to tell so in the .deployment file:

1
2
[config]
command = build.cmd

The build.cmd script itself is in three parts:

  1. Package restore: we retrieve paket.exe if it hasn't already been retrieved, and run it to restore packages.

    1
    2
    3
    4
    5
    
    if not exist .paket\paket.exe (
      .paket\paket.bootstrapper.exe
    )
    
    .paket\paket.exe restore
  2. Build: Azure conveniently points the environment variable MSBUILD_PATH to the path to MSBuild.exe; in order to be also able to run this script locally, we check for it and set it to the standard installation location if it doesn't exist. Then, we run it.

    1
    2
    3
    4
    5
    
    if "%MSBUILD_PATH%" == "" (
      set MSBUILD_PATH="%ProgramFiles(x86)%\MSBuild\12.0\Bin\MSBuild.exe"
    )
    
    %MSBUILD_PATH% /p:Configuration=Release
  3. Deploy: Deploying the application simply consists in copying the application files to the Azure-provided DEPLOYMENT_TARGET folder. The actual file in the 2048 repository is a bit more complex than necessary for Azure because it is also used on AppVeyor to deploy the application to github-pages. But a simple implementation can just copy all files and subdirectories from the project directory to DEPLOYMENT_TARGET:

    1
    2
    3
    
    if not "%DEPLOYMENT_TARGET%" == "" (
      xcopy /y /e <your_project_name> "%DEPLOYMENT_TARGET%"
    )

As a recap, here is the full build.cmd with some extra error management:

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
@ECHO OFF
setlocal

echo ====== Restoring packages... ======

if not exist .paket\paket.exe (
  .paket\paket.bootstrapper.exe
)

.paket\paket.exe restore

if not %ERRORLEVEL% == 0 (
  echo ====== Failed to restore packages. ======
  exit 1
)

echo ====== Building... ======

if "%MSBUILD_PATH%" == "" (
  set MSBUILD_PATH="%ProgramFiles(x86)%\MSBuild\12.0\Bin\MSBuild.exe"
)

%MSBUILD_PATH% /p:Configuration=Release

if not %ERRORLEVEL% == 0 (
  echo ====== Build failed. ======
  exit 1
)

if not "%DEPLOYMENT_TARGET%" == "" (
  echo ====== Deploying... ======
  xcopy /y /e <your_project_name> "%DEPLOYMENT_TARGET%"
)

echo ====== Done. ======

And there you have it! A WebSharper application easily deployed to Azure with a simple configuration and consistent build setup between local and deployed.

Note that this particular example is a Single-Page Application, but the same setup can be used for Client-Server Applications and HTML Applications. For the latter, make sure to copy the WebSharperHtmlDirectory (<your_project_name>/bin/html by default) in the final step rather than the project folder itself.

Thanks to Steffen Forkmann and Don Syme for their quick response on creating the FSharp.Compiler.Tools NuGet package, and to Scott Hanselman for his Suave Azure deployment tutorial which has been of great help to create this one despite the fairly different final setup.

Happy coding!

By Loïc Denuzière on Wednesday, May 6, 2015 — 0 comments

WebSharper 3.0.59 released Core team

This is the first minor release since WebSharper 3.0 went live. Here is the change log:

  • The types Web.IContext and Sitelets.Context<_> have a new member Environment : IDictionary<string, obj>. This property is used to pass host-specific data to sitelets and Rpc functions. Currently, this dictionary contains:
    • When running as an ASP.NET module (eg. Client-Server Application project template), "HttpContext" contains System.Web.HttpContext.Current.
    • When running on OWIN (eg. Self-Hosted Client-Server Application project template), "OwinContext" contains the current IOwinContext.

      Thanks to Catalin Bocirnea for this contribution on this!

  • Added a Sitelets.Content creation helper: Content.FromAsync : Async<Content<'T>> -> Content<'T>

  • Fixed #391: Sitelet.Infer would incorrectly match URLs longer than prescribed, for example a union case such as:

    1
    
    | Article of id: int

    would not only accept urls such as:

    1
    
    /Article/123

    but also urls with any extraneous fragments afterwards:

    1
    
    /Article/123/something-extra

    Now it only accepts urls with the following formats:

    1
    2
    
    /Article/123
    /Article/123/

As always, WebSharper 3.0.59 is available on NuGet, and the installers for Visual Studio and Xamarin Studio / MonoDevelop are available on the official website and on the respective update channels.

Happy coding!