Upload
truongquynh
View
214
Download
1
Embed Size (px)
Citation preview
What is WebSharper?
• F# Web Development Framework• Abstractions, abstractions everywhere
• Ecosystem (~50 extensions)• Full-stack F#, not only F#->Javascript compiler• Developed by IntelliFactory (~270 projects, all in F#), eating
their dog food• Apache license
Features
• Client-Server apps• Type system across client and server
• Plumbing for client-server apps• Idiomatic abstractions
• Pagelets• Sitelets• Formlets• Flowlets• Piglets
• Typed wrappers for Javascript libraries
When to use WebSharper?
• You love F#• You’re probably NOT in love with Javascript
When it’s „probabaly” not advised to use WebSharper?• You love Javascript• You just want something to spit some nice Javascript code• You can’t figure out what’s this Functional Programming buzz
all about
Starting with WebSharper
• Visual Studio• Nuget• vsix installer (with Visual Studio Templates)
• Xamarin Studio• Add-in
• CloudSharper• Web IDE, collaboration platform (Cloud)• Executed on local machine
WebSharper Code Sample
• Client-server
ASP.NET Integration
• Client-side controls• ... with Remoting
• In ASPX Pages• In Razor Pages• or as Sitelet
OWIN Integration
• WebSharper.Owin.RemotingMiddleware• WebSharper.Owin.SiteletMiddleware
Sitelets
• primary way to create server-side content• Route requests• Generate HTML or JSON responses
• Sitelets routing• Mapping from URLs to actions• Mapping from actions to URLs• Mapping from actions to content
• Custom Attributes to Sitelet.Infer
open WebSharper.Sitelets
type Action =| Index| Stats of username: string| BlogArticle of id: int * slug: string
type MyWebsite() =interface IWebsite<Action> with
member this.Sitelet =Sitelet.Infer <| function
| Index ->// Content of the index pageContent.PageContent <| fun ctx ->
{ Page.Default withTitle = Some "Welcome!"Body = [H1 [Text "Index page"]] }
| Stats username ->// Content of the stats page, which depends on the usernameContent.PageContent <| fun ctx ->
{ Page.Default withBody = [Text ("Stats for " + username)] }
| BlogArticle (id, slug) ->// Content of the article page, which depends on id and slugContent.PageContent <| fun ctx ->
{ Page.Default withBody = [Text (sprintf "Article id %i, slug %s" id slug)] }
member this.Actions = []
[<assembly: WebsiteAttribute(typeof<MyWebsite>)>]do ()
Sitelet.Infer Custom Attributes
• [<Method("GET", "POST", ...)>]• [<CompiledName "string">]• [<Query("arg1", "arg2", ...)>]• [<Json "arg">]• [<FormData("arg1", "arg2", ...)>]• [<DateTimeFormat(string)>]• [<Wildcard>]
module Content =open Http
val PageContent : (Context<'Action> -> Page) -> Content<'Action>val PageContentAsync : (Context<'Action> -> Async<Page>) -> Content<'Action>
val WithTemplate : Template<'T> -> (Context<'Action> -> 'T) -> Content<'Action>val WithTemplateAsync : Template<'T> -> (Context<'Action> -> Async<'T>) -> Content<'Action>
val JsonContent : (Context<'Action> -> 'T) -> Content<'Action>val JsonContentAsync : (Context<'Action> -> Async<'T>) -> Content<'Action>
val CustomContent : (Context<'Action> -> Response) -> Content<'Action>val CustomContentAsync : (Context<'Action> -> Async<Response>) -> Content<'Action>
module Content =/// Permanently redirect to an action. (HTTP status code 301)val Redirect : 'Action -> Content<'Action>
/// Permanently redirect to a URL. (HTTP status code 301)val RedirectToUrl : string -> Content<'Action>
/// Temporarily redirect to an action. (HTTP status code 307)val RedirectTemporary : 'Action -> Content<'Action>
/// Temporarily redirect to a URL. (HTTP status code 307)val RedirectTemporaryToUrl : string -> Content<'Action>
HTML Combinators
• Server-sidelet myDiv = Div []// HTML: <div></div>
let myRule = HR []// HTML: <hr/>
let mySection = Section [HR []]// HTML: <section><hr/></section>
let myP = P [Class "paragraph"] -< [Text "This is a paragraph."]// HTML: <p class="paragraph">This is a paragraph.</p>
• Client-side
HTML Templates
• ${NameOfHole}• data-replace="NameOfHole"• data-hole="NameOfHole"
UI.Next
• Reactive Web Development
open WebSharper.UI.Nextopen WebSharper.UI.Next.Html
let basicExample() =
let rvContent = Var.Create ""let vUpperContent =
rvContent.View|> View.Map (fun t -> t.ToUpper())
Div [] [Doc.Input [] rvContentLabel [] [Doc.TextView vUpperContent]
]
Formletstype Person = {
Name: stringEmail: string
}
[<JavaScript>]let PersonFormlet : Formlet<Person> =
let nameF = Controls.Input "" |> Validator.IsNotEmpty "Empty name not allowed" |> Enhance.WithValidationIcon|> Enhance.WithTextLabel "Name"
let emailF = Controls.Input ""|> Validator.IsEmail "Please enter valid email address" |> Enhance.WithValidationIcon|> Enhance.WithTextLabel "Email"
Formlet.Yield (fun name email -> {Name = name; Email = email})<*> nameF<*> emailF|> Enhance.WithSubmitAndResetButtons|> Enhance.WithLegend "Add a New Person"|> Enhance.WithFormContainer
[<JavaScript>]let Main () =
Div [PersonFormlet]
Piglets
• Yes...
• Similar to Formlets but gives you control over HTML generation
Extensions
• Sencha Architect• jQuery• Kendo UI• Google Visualization• Google Maps• D3, Raphael, Dojo• Babylon.js• ...
Deployment options
• OWIN Containers• IIS
• Azure Websites
namespace Samples
open WebSharper
open WebSharper.Html.Client
open WebSharper.Google.Maps
[<JavaScript>]
module GoogleMaps =
open WebSharper.JavaScript
let Sample buildMap =
Div [Attr.Style "padding-bottom:20px; width:500px; height:300px;"]
|>! OnAfterRender (fun mapElement ->
let center = new LatLng(37.4419, -122.1419)
let options = new MapOptions(center, 8)
let map = new Google.Maps.Map(mapElement.Body, options)
buildMap map)
let SimpleMap() =
Sample <| fun (map: Map) ->
let latLng = new LatLng(37.4419, -122.1419)
let options = new MapOptions(latLng, 8)
map.SetOptions options
let SimpleDirections() =
Sample <| fun map ->
let directionsService = new DirectionsService()
let directionsDisplay = new DirectionsRenderer();
map.SetCenter(new LatLng(41.850033, -87.6500523))
map.SetZoom 7
map.SetMapTypeId MapTypeId.ROADMAP
let a = DirectionsRendererOptions()
directionsDisplay.SetMap(map)
let mapDiv = map.GetDiv()
let dirPanel = Div [ Attr.Name "directionsDiv"]
let j = WebSharper.JQuery.JQuery.Of(mapDiv)
j.After(dirPanel.Dom).Ignore
directionsDisplay.SetPanel dirPanel.Body
let calcRoute () =
let start = "chicago, il"
let destination = "st louis, mo"
let request = new DirectionsRequest(start, destination, TravelMode.DRIVING)
directionsService.Route(request, fun (result, status) ->
if status = DirectionsStatus.OK then
directionsDisplay.SetDirections result)
calcRoute ()
Other web development options in F#
• Suave.io (simple web development F# library)• Pure F# ASP.NET MVC• FunScript (F# to javascript converter)• Freya (functional-first web stack)• Frank (combinators for composing web applications)• ServiceStack• NancyFx• Canopy (web testing framework)
How much does it cost?
• Free – $ 0• Mobile - $ 25 / month• Insider Basic (individual) - $ 299 / year• Insider Pro (company) - $ 899 / year
+ Support/Consulting/Training options
Resources
• http://websharper.com/docs• „Expert F# 3.0” Don Syme, Adam Granicz, Antonio Cisternino