A Simple Nowin F# Example
In my last post I showed a simple F# OWIN self hosted server without an application framework. Today I want to show an even simpler example that doesn’t reference any of the Microsoft OWIN libraries, but instead uses an open source server implementation, Nowin. Thanks to Damien Hickey for pointing me in the right direction.
The great thing about the Open Web Interface for .NET (OWIN) is that it is simply a specification. There is no OWIN library that you have to install to allow web servers, application frameworks and middlewear built to the OWIN standard to communicate. There is no interface that they must implement. They simply need to provide an entry point for the OWIN application delegate (better know as the AppFunc):
Func<IDictionary<string , object>, Task>
For simple applications, where we don’t need routing, authentication, serialization, or an application framework, this means we can simply provide our own implementation of the AppFunc and pass it directly to an OWIN web server.
Nowin, by Boris Letocha, is a .NET web server, built directly against the standard .NET socket API. This means it should work on all platforms that support .NET without modification. The author claims that it has equivalent performance to NodeJS on Windows and can even match HttpListener. Although not ready for production, it makes a compelling implementation for simple test servers and stubs, which is how I intend to use it.
To use any OWIN web server with F#, we simply need to provide an AppFunc and since F# lambdas have an implicit cast to System.Func<..> we can simply provide the AppFunc in the form:
fun (env: IDictionary<string, obj>) -> Task.FromResult(null) :> Task
Let’s see it in action. First create an F# console application and install the Nowin server with NuGet:
Install-Package Nowin
Now we can host our Nowin server in the application’s entry point:
[<entrypoint>]
let main argv =
use server =
Nowin.ServerBuilder
.New()
.SetEndPoint(new IPEndPoint(IPAddress.Any, port))
.SetOwinApp(fun env -> Task.FromResult(null) :> Task)
.Build()
server.Start()
printfn "Server listening on http://localhost:%i/ \nhit <enter> to stop." port
Console.ReadLine() |> ignore
0
Of course this server does nothing at all. It simply returns the default 200 OK response with no body. To do any useful work you need to read the OWIN environment, understand the request and create a response. To make this easier in F# I’ve created a simple OwinEnvironment type with just the properties I need. You could expand this to encompass whatever OWIN environment properties you need. Just look at the OWIN spec for this.
type OwinEnvironment = {
httpMethod: string;
requestBody: Stream;
responseBody: Stream;
setResponseStatusCode: (int -> unit);
setResponseReasonPhrase: (string -> unit)
}
Here is a function that takes the AppFunc environment and maps it to my OwinEnvironment type:
let getOwinEnvironment (env: IDictionary<string , obj>) = {
httpMethod = env.["owin.RequestMethod"] :?> string;
requestBody = env.["owin.RequestBody"] :?> Stream;
responseBody = env.["owin.ResponseBody"] :?> Stream;
setResponseStatusCode =
fun (statusCode: int) -> env.["owin.ResponseStatusCode"] <- statusCode
setResponseReasonPhrase =
fun (reasonPhrase: string) -> env.["owin.ResponseReasonPhrase"] <- reasonPhrase
}
Now that we have our strongly typed OwinEnvironment, we can grab the request stream and response stream and do some kind of mapping. Here is a function that does this. It also only accepts POST requests, but you could do whatever you like in the body. Note the transform function is where the work is done.
let handleOwinEnvironment (owin: OwinEnvironment) : unit =
use writer = new StreamWriter(owin.responseBody)
match owin.httpMethod with
| "POST" ->
use reader = new StreamReader(owin.requestBody)
writer.Write(transform(reader.ReadToEnd()))
| _ ->
owin.setResponseStatusCode 400
owin.setResponseReasonPhrase "Bad Request"
writer.Write("Only POST requests are allowed")
Just for completeness, here is a trivial transform example:
let transform (request: string) : string =
sprintf "%s transformed" request
Now we can re-visit our console Main function and pipe everything together:
[<entrypoint>]
let main argv =
use server =
Nowin.ServerBuilder
.New()
.SetEndPoint(new IPEndPoint(IPAddress.Any, port))
.SetOwinApp(fun env ->
env
|> getOwinEnvironment
|> handleOwinEnvironment
|> endWithCompletedTask)
.Build()
server.Start()
printfn "Server listening on http://localhost:%i/ \nhitto stop." port
Console.ReadLine() |> ignore
0
The endWithCompletedTask function, is a little convenience to hide the ugly synchronous Task return code:
let endWithCompletedTask = fun x -> Task.FromResult(null) :> Task
So as you can see, OWIN and Nowin make it very easy to create small web servers with F#. Next time you just need a simple service stub or test server, consider doing something like this, rather that using a heavyweight server and application framework such as IIS, MVC, WebAPI or WebForms.
You can find the complete code for the example in this Gist https://gist.github.com/mikehadlow/c88e82ee98619f22f174:
0 comments