The HTTP protocol adheres to the functional programming paradigm. This talk looks at HTTP on .NET and illustrates how F# allows for a more direct correlation to the patterns of composition inherent in the design of HTTP.
5. Current Options
O http.sys
O HttpListener
O IIS (IHttpModule & IHttpHandler)
O Web Forms
O MVC
O WCF HTTP & Data Services
6. Future Options
O System.Net.Http (BETA)
O .NET 4.5
O Available on NuGet
O ASP.NET Web API (BETA)
O Builds on System.Net.Http
O Integrated with MVC 4
7. OSS Options
Frameworks Servers
O FubuMVC O Firefly (OWIN)
O MonoRail O Fracture (F#)
O NancyFx
O Kayak (OWIN)
O OpenRasta
O Manos de Mono
O OWIN/Gate
O ServiceStack.NET O Mono XSP
O WebSharper
O … and many more!
9. Component Parts
O Request/Response Lines
O Methods, URIs, Status Codes
O Headers
O General, Request, Response, Content
O Resources
O Representations
O Hypermedia
15. HttpListener
O Low-level
O Defines the signature for a single application only
O HttpListenerContext provides a singleton; no
chance to intercept and chain behavior
O Routing requests requires custom handling;
typically by using imperative if-then-else
O No means of chaining or composing multiple
listeners
16. HttpListener
HttpListener.Start
("http://localhost:8082/", (fun (request, response) -> async {
match request.Url.LocalPath with
| "/post" ->
// Send message to the chat room
room.SendMessage(request.InputString)
response.Reply("OK")
| "/chat" ->
// Get messages from the chat room (asynchronously!)
let! text = room.AsyncGetContent()
response.Reply(text)
| s ->
// Handle an ordinary file request
let file =
root + (if s = "/" then "chat.html" else s.ToLower())
if File.Exists(file) then
let typ = contentTypes.[Path.GetExtension(file)]
response.Reply(typ, File.ReadAllBytes(file))
else
response.Reply(sprintf "File not found: %s" file) }),
cts.Token)
17. IHttpModule & IHttpHandler
O Low-level
O HttpContext has the same problems as
HttpListenerContext
O IHttpHandler could represent a Resource, but
method mapping is imperative
O IHttpModule provides a middleware layer for
routing or hosting multiple IHttpHandlers
O System.Web.Routing surfaces the routing
component
19. ASP.NET Web Forms
O HTML composition via
MasterPages, Pages, and Controls
O Suffers many problems associated with
IHttpModule and IHttpHandler
O Evented model allows for interception
O No built-in support for other representations
O Pages loosely correlate to Resources
O Application composition and routing by file
path
20. ASP.NET MVC
O Suffers many problems associated with
IHttpModule and IHttpHandler
O Primarily HTML generation but allows for better
HTTP control
O Built-in support for handling Ajax requests
O ActionFilters allow for behavior composition at
different points:
Authorize, ActionExecuting, ActionExecuted, Resul
tExecuting, ResultExecuted
21. ASP.NET MVC, cont.
O Content Negotiation is still very manual
O ViewEngines and Serializers can be made to
render various representations
O ViewEngines offer representation composition
O Controllers ~ Resources, but not quite
O Areas and Routing allow for Nested
Resources, to a degree
22. Problem Summary
O Have:
O Limited interception for cross-cutting
concerns
O Representation composition
O Do not have:
O No easy resource composition
O No built-in content negotiation
23. Composition for Conneg
O Rendering
O Imperative if-then-else
O Serializers
O Location
O Within the specific method handler (common for
imperative)
O Top-level (common for serializers)
O Why not both?
24. Nested Resources
O Imperative if-then-else
O Routing
O MVC Areas offer another level
O What about more than one level?
O Rails – problem with deep URIs
O System.Web.Routing does everything at the
top-level, so tracking deeper resource trees is
difficult.
27. Frank
O F# DSL using System.Net.Http
O Headers composition
O Follows the natural composition of HTTP
O Frank Resources == HTTP Resources
O Define your own conventions!
29. Define a Method Handler
// handler
let echo request = async {
let! body = request.Content.AsyncReadAsString()
return HttpResponseMessage.ReplyTo(request, body)
}
// method handler
get echo
30. Define a Resource
let helloworld request = async { … }
let echo request = async { … }
let resource = route “/” (get helloworld <|> post echo)
31. Define an Application
let todoListResource = route “/” (get todoList <|> …)
let todoItemResource = route “/item/{1}” (put …)
let app = merge [ todoListResource; todoItemResource ]
32. Leverage Conneg
val negotiateMediaType = formatters ->
HttpRequestMessage ->
string ->
Async<HttpResponseMessage>
let echo = negotiateMediaType formatters
<| fun request ->
request.Content.AsyncReadAsString())
33. WebSharper
O One language for both client and server
O Can leverage to cleanly separate parts
O Use WebSharper to generate code-on-
demand to send to the client
O Plays well with existing tools
35. Resources
O ASP.NET Web Forms in F#
O ASP.NET MVC in F#
O Figment DSL for MVC
O Frank DSL for Web API
O WebSharper
O Pit FW
36. Thank you!
O Please rate this talk:
http://speakerrate.com/talks/9293-the-
functional-web
Notes de l'éditeur
HTTP defines several components that allow distributed, loosely-coupled agents to communicate. The first lines of requests and responses are standardized to ensure that loosely-coupled components can understand one another, yet they allow for extension either by standards bodies or for internal, proprietary use.
This may be new to some, but this resource is not the same as the collection of items at /items.
The aggregate of many resources is generally what we refer to as an HTTP, or Web, Application. A single resource is enough, as is a single method.
Resources may be directly returned in a response. In the beginning, when most HTTP applications served static files, this was common. However, Resources are not equivalent to the representation returned to the client, even if they appear identical. Unlike editing files locally, if you were to edit a file returned from an HTTP application, you would not be editing the original file. You would need to re-submit the file to the server, if allowed, and then the server would need to take the content you supplied and update the original Resource.It is thus reasonable to understand that a Resource can be represented in more than one way. A JSON representation is just as valid as XML, HTML, or even an image.Content negotiation, or “conneg,” is a cross-cutting concern that allows HTTP applications to select an appropriate representation to send in the response message. The actual execution of this selection could occur either at the top-level or at the lowest-level of a composed HTTP application.
It’s also important to note that the request and response headers are just NameValueCollections, so you don’t have easy, typed access to common header values. This isn’t critical for composition but odd for a statically-typed language platform.DEMO: In spite of its short-comings, you can still do some interesting things with HttpListener. Tomas Petricek created a really interesting project where he uses HttpListener as the base for a chat server.
It’s also important to note that the request and response headers are just NameValueCollections, so you don’t have easy, typed access to common header values. This isn’t critical for composition but odd for a statically-typed language platform.DEMO: In spite of its short-comings, you can still do some interesting things with HttpListener. Tomas Petricek created a really interesting project where he uses HttpListener as the base for a chat server.
It’s important to note here that these interfaces are exposed by IIS and can be used to modify that server directly, though they are also tied directly to that server. Mono offers additional options for hosting, but you should understand that you are generally tied to IIS.
It’s important to note here that these interfaces are exposed by IIS and can be used to modify that server directly, though they are also tied directly to that server. Mono offers additional options for hosting, but you should understand that you are generally tied to IIS.
ASP.NET Web Forms 4.0 provided a hook intoSystem.Web.Routing.Also of note:Web Forms has historically been demonized by it’s poor HTML output, requiring a <form> element to scope control usage.Many server controls have weird behavior. Anchor tags, which generally perform GET requests instead POST back to server, even just to navigate to another page. Some of this is of course avoidable, but the designer-centric focus often leads to ill-advised HTTP use.FSharpCodeDomProvider has limitations.
Also difficult to use F# for View Models. You will have a difficult time using records and discriminated unions as types, and you’ll be forced into mutability.
Current frameworks typically choose to lean on one or the other of the above sets of options. However, there really should be no reason to require only one or the other. In fact, you should be free to define various boundaries where you might use a serializer approach over a subset of resources.
Routing is nothing more than filtering down a set of handlers to select the appropriate one and return a response.A Response is nothing more than a map function over a request, though it is true that some HTTP methods are destructive (e.g. POST).Pulling handlers into resources or applications is nothing more than a reduce function. Frank uses merge; WebSharper uses Sum.
For those with a stronger bent towards building web sites, Mauricio Scheffer’s Figment may be a closer match to your taste.
Compare the Frank application signature with the simplest app signature we used above. The only addition is that we are stating that an application is non-blocking. This is the same idea as is used in node.js. It’s also sort-of required since Frank sits on System.Net.Http via MessageHandlers. The signature for the MessageHandler.SendAsync is the same but for Task rather than Async. This signature extends all the way through all layers of composition.
A resource is the only current location that does not conform solely to the Frank application signature. A resource holds both a Uri Template (its name) as well as a HttpRequestMessage -> Async<HttpResponseMessage> option. Why the option? The resource will respond with a 405 Method Not Allowed if it does not respond to the method thrown its way. Thus the option allows the programmer to define the methods for the resource without having to manually hook up the 405 response.
Similar to resource, merge is a function of HttpRequestMessage -> Async<HttpResponseMessage> option. When a resource uri is not found, a 404 Not Found response is returned. The result, however, is a Frank application.
Frank currently uses Mauricio Scheffer’sFsConneg library, now in FSharpx.Http. System.Net.Http has a similar mechanism, but it’s currently still a little heavy as they work out the kinks in preparation for the RC. FsConneg provides a mechanism for submitting the Accept headers and a list of supported formats and returns the best match. negotiateMediaType wraps that with the selection of the appropriate formatter, of type System.Net.Http.Formatting.MediaTypeFormatter, and returns the formatted content.
Another option is Pit FW, which was featured on the Community for F# on 2/21/2012 (today). It also compiles F# to JavaScript. You can learn more at http://pitfw.org/.
Using F# for web projects isn’t just about code size. Yes, you’ll save some lines of code, but more importantly, you’ll work closer to the guts of HTTP. You can leverage the power of composition to build applications that will be more maintainable and much clearer to understand.