Search code examples
f#owintopshelf

Topshelf, Owin selfhost, F# and explicit fields


I've installed the package Topshelf.FSharp, and there is an example of how to use it here:

https://gist.github.com/haf/4252121

Part of the example defines an "Svc" (service) class like this:

type Svc() =
  member x.Start() =
    printfn "Started"
  member x.Stop() =
    printfn "Stopped"

With Owin selfhost you call one of the various static overloads of IDisposable WebApp.Start(...) to start a web server, and then dispose it to stop it. In C#, if you want to combine Topshelf and Owin, you can store the IDisposable result of Start() in a private local field of the Svc class when Start() is called, and then call Dispose() on it in the Stop() method.

In F# you can declare an unitialized field of type IDisposable using "explicit fields" (http://msdn.microsoft.com/en-us/library/dd469494.aspx), but this seems somewhat awkward, is there a better way?


Solution

  • You do not have to use an explicit field to produce an "uninitialized" IDisposable value. For example, to define a restartable service, you can use an implicit webApp field like this:

    // Example 1: Using an implicit mutable IDisposable field.  
    type Svc() =
        let mutable webApp = null
    
        member __.Start() = 
            if webApp = null then webApp <- WebApp.Start<Startup> "http://localhost:12345"
    
        member __.Stop() = 
            if webApp <> null then webApp.Dispose(); webApp <- null
    
    // Example 2: Using an implicit mutable IDisposable option field.  
    type Svc'() =
        let mutable webApp = None
    
        member __.Start() = 
            match webApp with 
                | Some _ -> () 
                | None -> webApp <- Some(WebApp.Start<Startup> "http://localhost:12345")
    
        member __.Stop() = 
            match webApp with 
                | Some webAppValue -> webAppValue.Dispose(); webApp <- None
                | None -> ()
    

    If the service does not have to be restartable, I would use an (immutable) implicit lazy field instead, as @Tom suggested.