Declarative authorization in REST services in SharePoint with F# and ServiceStack

This post is a short overview of my talk at Belarus SharePoint User Group at 2013/06/27.

The primary goals were to find an efficient declarative way to specify authorization on REST service (that knows about SharePoint built in security model) and try F# in SharePoint on a real-life problem. Service Stack was selected over ASP.NET Web API because I wanted to find a solution that operates in SharePoint 2010 on .NET 3.5.

ServiceStack: F# Client Application

In the previous post “ServiceStack: New API – F# Sample (Web Service out of a web server)” we implemented a self-hosted service with ServiceStack. That service has multiple out-of-the-box endpoints, including a REST one.

The next interesting question is “How to call this service?”(preferably in a strongly-typed way). The answer is simple, ServiceStack team have already made ​​this for us.  We can reuse types that designed for server-side code to make client code prettier. ServiceStack provides a list of different service clients for client applications.

open System
open ServiceStack.ServiceHost
open ServiceStack.ServiceClient.Web

[<CLIMutable>]
type HelloResponse = { Result:string }

[<Route("/hello")>]
[<Route("/hello/{Name}")>]
type Hello() =
    interface IReturn<HelloResponse>
    member val Name = "" with get, set

let baseUri = "http://localhost:8080/"

// Option 1 : Json call
let jsonCall() =
    let client = new JsonServiceClient(baseUri)
    client.Post(Hello(Name="json"))

// Option 2 : Xml call
let xmlCall() =
    let client = new XmlServiceClient(baseUri)
    client.Post(Hello(Name="xml"))

// Option 3: Jsv call
let jsvCall() =
    let client = new JsvServiceClient(baseUri)
    client.Post(Hello(Name="jsv"))

[<EntryPoint>]
let main args =
    printfn "Json call : %A" (jsonCall())
    printfn "Xml call : %A" (xmlCall())
    printfn "Jsv call : %A" (jsvCall())
    Console.ReadLine() |> ignore
    0

ServiceStack: New API – F# Sample (Web Service out of a web server)

Two weeks ago in F# Weekle #6 2013 I mentioned Don Syme’s “F# + ServiceStack – F# Web Services on any platform in and out of a web server” post. There were two samples of  using ServiceStack from F#. One of these examples is given on ServiceStack wiki page in Self Hosting section. It is also detailed in Demis Bellot’s “F# Web Services on any platform in and out of a web server!” post.

Unfortunately, this example is already obsolete. Some time ago, ServiceStack released a brand new API that significantly changed programming approach, especially routing (for details see “ServiceStack’s new API design“). But I am happy to say that you can find an updated example below!

New design is more typed. In the previous version IService‘s methods returned the Object, but now Service returns concrete type that is defined by IReturn<T> interface of request message.

open System
open ServiceStack.ServiceHost
open ServiceStack.WebHost.Endpoints
open ServiceStack.ServiceInterface

[<CLIMutable>]
type HelloResponse = { Result:string }

[<Route("/hello")>]
[<Route("/hello/{Name}")>]
type Hello() =
    interface IReturn<HelloResponse>
    member val Name = "" with get, set

type HelloService() =
    inherit Service()
    member this.Any (request:Hello) =
        {Result = "Hello," + request.Name}

//Define the Web Services AppHost
type AppHost() =
    inherit AppHostHttpListenerBase("Hello F# Services", typeof<HelloService>.Assembly)
    override this.Configure container = ignore()

//Run it!
[<EntryPoint>]
let main args =
    let host = if args.Length = 0 then "http://*:8080/" else args.[0]
    printfn "listening on %s ..." host
    let appHost = new AppHost()
    appHost.Init()
    appHost.Start host
    Console.ReadLine() |> ignore
    0

For comparison, the previous version is:

open System
open ServiceStack.ServiceHost
open ServiceStack.WebHost.Endpoints

type Hello = { mutable Name: string; }
type HelloResponse = { mutable Result: string; }
type HelloService() =
    interface IService with
        member this.Any (req:Hello) = { Result = "Hello, " + req.Name }

//Define the Web Services AppHost
type AppHost =
    inherit AppHostHttpListenerBase
    new() = { inherit AppHostHttpListenerBase("Hello F# Services", typeof<HelloService>.Assembly) }
    override this.Configure container =
        base.Routes
            .Add<Hello>("/hello")
            .Add<Hello>("/hello/{Name}") |> ignore

//Run it!
[<EntryPoint>]
let main args =
    let host = if args.Length = 0 then "http://*:1337/" else args.[0]
    printfn "listening on %s ..." host
    let appHost = new AppHost()
    appHost.Init()
    appHost.Start host
    Console.ReadLine() |> ignore
    0

Update: An example of ServiceStack New API for F# 2.0 users. F# 2.0 does not have val keyword / auto-properties which were used in the first example.

</pre>
open System
open ServiceStack.ServiceHost
open ServiceStack.WebHost.Endpoints
open ServiceStack.ServiceInterface

type Project() =
    let mutable projectID = 0
    let mutable projectName = ""
    let mutable companyName = ""
    let mutable projectStatus = ""
    member this.ProjectID with get() = projectID and set(pid) = projectID <-pid
    member this.ProjectName with get() = projectName and set(pn) = projectName <- pn
    member this.CompanyName with get() = companyName and set(cn) = companyName <- cn
    member this.ProjectStatus with get() = projectStatus and set(ps) = projectStatus <-ps

type ProjectResponse() =
    let mutable projects = List.empty<Project>
    member this.Projects with get() = projects and set(pr) = projects <- pr

[<Route("/Project/{ProjectName}")>]
type ProjectRequest() =
    let mutable projectName = ""
    interface IReturn<ProjectResponse>
    member this.ProjectName with get() = projectName and set(n) = projectName <- n

type ProjectService() =
    inherit Service()
    member this.Any (request:ProjectRequest) =
        ProjectResponse(
             Projects = [Project(ProjectName=request.ProjectName, ProjectID=1, CompanyName="A")])

//Define the Web Services AppHost
type AppHost() =
    inherit AppHostHttpListenerBase("Project F# Services", typeof<ProjectService>.Assembly)
    override this.Configure container = ignore()

//Run it!
[<EntryPoint>]
let main args =
    let host = if args.Length = 0 then "http://*:8080/" else args.[0]
    printfn "listening on %s ..." host
    let appHost = new AppHost()
    appHost.Init()
    appHost.Start host
    Console.ReadLine() |> ignore
    0
<pre>