By Adam Granicz on Tuesday, August 4, 2015 — 0 comments

Introducing Try WebSharperCore team

We are thrilled to announce the availability of Try WebSharper, a simple and fun way to create and share WebSharper snippets with others!

The code you share can be run (=>Run) right in your browser, and you get basic type checking with warnings and errors showing up as red/yellow squiggles. Currently, this takes a couple seconds to complete so it's not the most convenient way to experiment, but it will get a lot better soon.

We aim to keep this site current with upcoming WebSharper releases, so you can use it to experiment with even the newest WebSharper features, including reactive markup and templating via UI.Next.

Converting F# snippets to WebSharper

While Try WebSharper is intended primarily for sharing WebSharper snippets (e.g. F# snippets that produce web output), you can also convert simple F# snippets by following a few simple steps.

Say, you wanted to run the following:

1
2
3
open System

sprintf "Time now is %s" (DateTime.Now.ToShortTimeString())

First, it helps to understand that snippets are not simply run as written in F#; they are converted to JavaScript with WebSharper and executed in your browser. For this, we use the single-page application (SPA) WebSharper template. This takes a master HTML document (index.html - and you can write to this file on the second tab) that references the JavaScript code generated from your F# code.

Using JS.Alert

In order for this to have a visible effect, you could simply raise a JavaScript popup with your output:

1
2
3
4
5
6
7
8
open System
open WebSharper
open WebSharper.JavaScript

[<JavaScript>]
let Main =
    sprintf "Time now is %s" (DateTime.Now.ToShortTimeString())
    |> JS.Alert

Note that you will always need to open WebSharper for the [<JavaScript>] attribute and other WebSharper pervasives, and it's also handy to open WebSharper.JavaScript for client-side/EcmaScript functions like JS.Alert.

Caveat

You may be tempted to throw away the name of the top-level binding, but this will yield no output due to let _ = ... being interpreted as do ... - which acts as a module initializer (instead of a top-level binding) that currently is not translated to JavaScript by WebSharper.

1
2
[<JavaScript>]
let _ =  ...

Using WebSharper.Html.Client

Another thing you can do is to show it in the markup that is rendered from index.html as your output. Note, that by default this document has a div node with id=main, which you can write to using the AppendTo member on any HTML.Client element.

1
2
3
4
5
6
7
8
9
open System
open WebSharper
open WebSharper.JavaScript
open WebSharper.Html.Client

[<JavaScript>]
let Main =
    Div([Text (sprintf "Time now is %s" (DateTime.Now.ToLongTimeString()))])
       .AppendTo "main"

Here, you are opening WebSharper.Html.Client for accessing client-side HTML functions like Div.

Using WebSharper.UI.Next

If you followed our recent announcements for WebSharper 3.4, you will likely prefer to do the above via the more flexible reactive HTML language introduced via UI.Next. Here is how that goes:

1
2
3
4
5
6
7
8
9
open System
open WebSharper    
open WebSharper.UI.Next.Html
open WebSharper.UI.Next.Client

[<JavaScript>]
let Main =
    div [text (sprintf "Time now is %s" (DateTime.Now.ToLongTimeString()))]
    |> Doc.RunById "main"

So all in all, these should give you three different strategies to convert F# snippets into WebSharper ones.

Site features and plans

As a code snippets site, Try WebSharper has the usual toolset for snippets: you can create a new snippet by hitting the big red plus (+) button in the bottom right corner, fork an existing snippet (=>Fork), or save the one you are working on (=>Save).

We also added a basic set of examples (with more being moved from WebSharper examples), which you can find under the hamburger icon, along with any saved snippets you may have:

Coming up

In future releases, we will be introducing additional functionality to help with "templating" basic snippets using any one of the above methods, spinning up snippets via GitHub gists, and lighting up much more refined code assistance services (code completion, type checking as you type, hover comments and signatures, etc.)

Happy sharing!

By Loïc Denuzière on Monday, August 3, 2015 — 3 comments

WebSharper UI.Next 3.4: the new HTML syntaxCore team

As its name suggests, UI.Next was created to be the next-generation standard library for UI programming in WebSharper. As a consequence, as of WebSharper 4.0, UI.Next will be merged into WebSharper itself under a less "codenamey" moniker that we haven't decided yet. It will completely obsolete the current Html.Client and Html.Server.

The recently released version 3.4 prepares the terrain for this merger. It streamlines the embedded markup syntax, introduces server-side capability and adds client-side functionality.

Streamlined syntax

WebSharper UI.Next 3.4 overhauls the syntax for embedding HTML elements in F# for enhanced readability and familiarity.

The most visible change is the switch to lowercase elements and attributes, making UI.Next code more similar to what you would write in an HTML file. For elements, the function Div0 which creates a <div> tag with child elements becomes simply div, and Div which creates a <div> tag with attributes and child elements becomes divAttr. For attributes, the class attr contains static methods to create standard attributes and on creates event handlers. Here is a list of the new constructors available under WebSharper.UI.Next.Html:

New syntax

Old / Verbose syntax

divAttr [attrs...] [children...]

Div [attrs...] [children...]

div [children...]

Div0 [children...]

text "Hello"

Doc.TextNode "Hello"

textView aView

Doc.TextView aView

Needs open WebSharper.UI.Next.Client

attr.color "black"

Attr.Create Attributes.Color "black"

attr.colorDyn aView

Attr.Dynamic Attributes.Color aView

Needs open WebSharper.UI.Next.Client

attr.colorDynPred aView aBoolView

Attr.DynamicPred Attributes.Color aBoolView aView

Needs open WebSharper.UI.Next.Client

attr.anim aView aFunc aTrans

Attr.Animated aTrans aView aFunc

Needs open WebSharper.UI.Next.Client

See "Tier-specific functionality" below for the rationale behind needing open WebSharper.UI.Next.Client for some of these.

Here is a small code sample:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/// New syntax                              │ /// Old syntax
open WebSharper.UI.Next                     │ open WebSharper.UI.Next
open WebSharper.UI.Next.Html                │ open WebSharper.UI.Next.Html
open WebSharper.UI.Next.Client              │
                                            │
let myDocument =                            │ let myDocument =
  let rvInput = Var.Create ""               │   let rvInput = Var.Create ""
  div [                                     │   Div0 [
    h1 [text "A small example"]             │     H10 [Doc.TextNode "A small example"]
    label [text "Type something here: "]    │     Label0 [Doc.TextNode "Type something here: "]
    Doc.Input [] rvInput                    │     Doc.Input [] rvInput
    pAttr [attr.``class`` "paragraph"] [    │     P [Attr.Create Attributes.Class "paragraph"] [
      text "You typed: "                    │       Doc.TextNode "You typed: "
      textView rvInput.View                 │       Doc.TextView rvInput.View
    ]                                       │     ]
  ]                                         │   ]

Server-side markup

It is now possible to use the Doc type, and the above syntax, to create server-side markup, ie. markup that is generated on the server and output in the HTML document, as opposed to client-side markup, generated dynamically in JavaScript.

Returning a server-side Doc as content

There are two ways to use a Doc as server-side content:

  • Use Content.Doc to create a Sitelets Content<_> value:

    1
    2
    3
    4
    5
    6
    7
    8
    
    open WebSharper.Sitelets
    open WebSharper.UI.Next
    open WebSharper.UI.Next.Server
    
    [<Website>]
    let MyWebsite =
      Application.SinglePage <| fun context ->
        Content.Doc myDocument
  • Convert it to Html.Server elements using Doc.AsElements:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    open WebSharper.Sitelets
    open WebSharper.UI.Next
    open WebSharper.UI.Next.Server
    
    [<Website>]
    let MyWebsite =
      Application.SinglePage <| fun context ->
        Content.Page(
          Body = Doc.AsElements myDocument
        )

Including client-side markup

In order to include a client-generated Doc inside a server-side Doc, you can use the function client. This function is analogous to ClientSide from Html.Server: it takes a quotation of a top-level, [<JavaScript>]-annotated function and includes it in server-side markup.

You can also add event handlers on server-side Docs using the methods in the on class. These methods take a quotation of a top-level, [<JavaScript>]-annotated function and return an Attr value that sets the handler as a static attribute on the element. This means that only one handler of a given type can be added to an element this way: you can't have two instances of eg. on.click <@ ... @> on the same server-side Doc.

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
open WebSharper
open WebSharper.UI.Next
open WebSharper.UI.Next.Html

[<JavaScript>]
module Client =
  open WebSharper.JavaScript
  open WebSharper.UI.Next.Client
  
  let Widget() =
    let rvInput = Var.Create ""
    Doc.Concat [
      Doc.Input [] rvInput
      p [text "You typed: "; textView rvInput.View]
    ]
    
  let Alert el ev =
    JS.Alert "Clicked!"

module Server =
  open WebSharper.Sitelets
  open WebSharper.UI.Next.Server

  [<Website>]
  let MyWebsite =
    Application.SinglePage <| fun context ->
      Content.Doc(
        div [
          h1 [text "Enter text below"]
          client <@ Client.Widget() @>
          buttonAttr [on.click <@ Client.Alert @>] [text "Click me!"]
        ]
      )

Tier-specific functionality

Some Doc functionality is only available on the client, or only on the server. To use such functionality, you need to open WebSharper.UI.Next.Client or WebSharper.UI.Next.Server, respectively.

The following is only available on the client side, and will raise a runtime error if used from the server side:

  • Reactive elements and attributes: textView, Doc.EmbedView, attr.*Dyn, attr.*DynPred, attr.*Anim, Doc.Convert*, reactive form elements (Doc.Input, etc).
  • Doc.Run, Doc.RunById, Doc.AsPagelet
  • on.* event handlers taking a function as argument. On the server you must use the version taking a quotation as argument.
  • Element methods and properties described below in "New client-side functionality".

The following is only available on the server side, and will raise a compile-time error if used from the client side:

  • Content.Doc, Doc.AsElements, Attr.AsAttributes.

New client-side functionality and the Elt type

One challenge in entirely replacing Html.Client with Doc is that existing applications using Html.Client should be convertible without requiring a complete change in paradigm. This means that we need to add as much of the imperative capabilities of Html.Client to Doc as possible. However, a Doc value is not guaranteed to be composed of a single root element, so accessing the element to perform actions such as SetAttribute or Append cannot be guaranteed to succeed. To fix this, we made the following change to the API.

The Doc type is now an abstract class, and there is a new type Elt that inherits from it and represents docs that are guaranteed to be composed of a single root element. The following functions return an Elt:

  • Element constructors, such as div and divAttr.
  • Doc.Element, Doc.SvgElement, Doc.Static.
  • Form input element constructors: Doc.Input, Doc.Button, etc.

Values of type Elt, in addition to being Docs, also have the following properties and methods (non-exhaustive list):

  • Dom returns the underlying Dom.Element.
  • Append(doc) and Prepend(doc) add child Docs to the beginning / end of the element. Reactive Docs are properly handled.
  • Clear() removes all children. Reactive children are properly disconnected from the View graph.
  • Text gets or sets the text content. The setter properly disconnects reactive children from the View graph.
  • Value gets or sets the value.
  • Methods to get, set, remove, test the presence of attributes, classes, styles: GetAttribute, SetProperty, HasClass, etc.
  • On "eventName" function adds an event callback.

We are still ironing out tricky parts required to implement OnAfterRender, which is quite ubiquitous in Html.Client code.

Templating language change

In order to allow using ${string} holes from the server side, the following change has been implemented:

  • ${string} holes now have type string instead of View<string>.
  • $!{string} is the new syntax for holes of type View<string>.

Conclusion

As you can see, a lot of enhancements are necessary to allow UI.Next markup to be usable as a replacement of Html.Client and Html.Server. We are confident that these changes will make it easy to convert existing applications to UI.Next for WebSharper 4.0.

Happy coding!

By Loïc Denuzière on Monday, August 3, 2015 — 4 comments

WebSharper 3.4 releasedCore team

We are happy to announce the availability of WebSharper 3.4, which you can download here. Here are the main highlights of this release.

Revamped Sitelets API

The sitelets API has received a well-needed cleanup and simplification.

  • Content is now always asynchronous: constructors and combinators take and return values of type Async<Content<_>>.

  • Context is now always passed from the sitelet to the content, rather than as a callback when constructing the content.

  • Content creation functions have been renamed:
    • Content.PageContent[Async] --> Content.Page overloaded with named arguments instead of a record
    • Content.JsonContent[Async] --> Content.Json
    • Content.CustomContent[Async] --> Content.Custom
    • Content.Text was added.
    • Content.File was added.

  • A new module WebSharper.Application contains functions to create sitelets:
    • MultiPage is equivalent to Sitelet.Infer.
    • SinglePage creates a sitelet with a single endpoint (action) and HTML content.
    • Text creates a sitelet with a single endpoint and text content.

Here is a small before/after comparison on a small 2-page 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
40
41
42
open WebSharper
open WebSharper.Sitelets

type EndPoint =
    | [<EndPoint "GET /">] Home
    | [<EndPoint "GET /api">] Api

// WebSharper 3.3

let HomePage =
    Content.PageContent <| fun ctx ->
        { Page.Default with
            Title = Some "Home"
            Body = [A [HRef (ctx.Link Action.Home)] -< [Text "This is the home page."]]
        }

let ApiPage =
    Content.JsonContent <| fun ctx ->
        ["a value"; "serialized"; "to json"]

[<Website>]
let MyWebsite =
    Sitelet.Infer <| function
        | Action.Home -> HomePage
        | Action.Api -> ApiPage

// WebSharper 3.4

let HomePage (ctx: Context<EndPoint>) =
    Content.Page(
        Title = "Home",
        Body = [A [HRef (ctx.Link Action.Home)] -< [Text "This is the home page."]]
    )

let ApiPage =
    Content.Json ["a value"; "serialized"; "to json"]

[<Website>]
let MyWebsite =
    Application.MultiPage <| fun ctx -> function
        | Action.Home -> HomePage ctx
        | Action.Api -> ApiPage ctx

A number of these new functions are equivalent to functions that were in WebSharper.Warp, which are now marked as obsolete.

New HTML language for UI.Next

We completely redesigned the HTML embedded language for WebSharper UI.Next. We will post another blog entry soon to fully describe the new design, but here are the main take-aways:

  • Element and attribute combinators are now lowercase, for a hopefully more natural-looking syntax.
  • The type Doc can be used for both client-side and server-side markup. Some features are only available on one side, such as UI.Next reactive elements for the client and conversion to a Content<_> for the server. To use these features, you need to open WebSharper.UI.Next.Client or WebSharper.UI.Next.Server, respectively.
    A template for client-server UI.Next applications has also been added to the Visual Studio and Xamarin Studio extensions.

Our goal for WebSharper 4.0 is to obsolete the current Html.Client and Html.Server, and to merge WebSharper.UI.Next into WebSharper under a new name. Doc will be the unique way to deal with HTML content, both on the client and the server side.

F# 4.0 proxies

WebSharper 3.4 provides JavaScript proxies for the functions that were added to the standard library in F# 4.0. You can now call functions such as Seq.mapFold and Array.last from the client-side.

Cross-site features for RPC functions

WebSharper 3.4 integrates several features related to cross-site requests to RPC functions:

  • Protection against Cross-Site Request Forgery using a cookie-to-header token. This protection is active by default and completely automatic.
    If you need to deactivate it, in particular to be able to call RPC functions from a PhoneGap mobile application, you can simply call DisableCsrfProtection() from module WebSharper.Web.Remoting at the top-level on the server side.
  • Management of allowed CORS origins. In module WebSharper.Web.Remoting, the functions AddAllowedOrigin and associated can be called at the top-level on the server side to add CORS origins accepted by the RPC handler. In particular, PhoneGap applications need to add file:// as an allowed origin.

Other changes

Here are the minor changes and bug fixes for WebSharper 3.4:

  • Fix #453: whitespace around the title in Content.Page.
  • Fix #459: Error 500 when replying to an RPC from a page with url "file://..."

Happy coding!

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

WebSharper 3.3 released with client-side JSON serializationCore 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 releasedCore 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 releasedCore 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 WarpCore 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:

Gitter

Happy coding!

By Frank Joppe on Monday, June 15, 2015 — 0 comments

Timesheet in WebsharperCommunity

Long time no blog, because I prefer to blog about stuff that I finished. However my current fsharp / Websharper project takes some time, and because of working conditions (little time to spend) it will take even quite some more time. So let’s write something about unfinished business. I work at a contractor company, and we have the process that every employee needs to submit their time spend in a timesheet at the end of the week and month. And then the invoice process works based on this [...[...]
>> Read the full article on fjoppe.weebly.com
By Adam Granicz on Tuesday, June 9, 2015 — 1 comment

WebSharper 3.2 with support for scriptable applications, better resource management, and additional streamlined syntaxCore 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 publishedCore 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!

TryWebSharper screenshot

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