在Owin应用程序中安装Suave

时间:2016-08-13 21:32:34

标签: f# owin suave

我有一个用C#编写的现有owin应用程序,并希望将一个suave应用程序作为中间件安装,但由于我对F#相对较新,我发现很难理解应该如何完成。我想我正在寻找类似的东西:

// in F# land
module MySuaveApp.ApiModule

let app =
  choose
    [ GET >=> choose
        [ path "/hello" >=> OK "Hello GET"
          path "/goodbye" >=> OK "Good bye GET" ]
      POST >=> choose
        [ path "/hello" >=> OK "Hello POST"
          path "/goodbye" >=> OK "Good bye POST" ] ]

  let getSuaveAsMiddleware() =
    ... magic goes here ...

// in Startup.cs
app.Use(MySuaveApp.ApiModule.getSuaveAsMiddleware())

至于那个魔法应该是什么,我认为它是OwinApp.ofAppFuncOwinApp.ofMidFunc的组合,但我不能为我的生活弄清楚应该是什么。

1 个答案:

答案 0 :(得分:5)

没有简单的魔法。 1 ofAppFuncofMidFunc用于从OWIN组件中创建WebPart,即OWIN - >温文尔雅,而你想要Suave - > OWIN。

以下适用于您的“应用程序”,并作为使其运行所需的示例:

open System.Runtime.CompilerServices

[<Extension>]
module Api = 
    open Suave
    open Successful
    open Filters
    open Operators
    open Microsoft.Owin
    open System.Threading.Tasks

    let app = 
        choose [ GET >=> choose [ path "/hello" >=> OK "Hello GET"
                                  path "/goodbye" >=> OK "Good bye GET" ]
                 POST >=> choose [ path "/hello" >=> OK "Hello POST"
                                   path "/goodbye" >=> OK "Good bye POST" ] ]

    let withCtx (ctx : IOwinContext) webpart =
        async {
            let request =
                { HttpRequest.empty with
                    headers = ctx.Request.Headers |> List.ofSeq |> List.map (fun kvp -> kvp.Key, kvp.Value |> String.concat ",")
                    host = ctx.Request.Host.Value 
                    ``method`` = HttpMethod.parse ctx.Request.Method
                    url = ctx.Request.Uri }
            let! res = webpart { HttpContext.empty with request = request }
            res |> Option.iter (fun r ->
                ctx.Response.StatusCode <- r.response.status.code
                match r.response.content with
                | Bytes bs -> ctx.Response.Write bs
                | _ -> failwith "Not supported")
            return res
        }

    type SuaveMiddleware(n) =
        inherit OwinMiddleware(n)
        override __.Invoke(context : IOwinContext) =
            let res = withCtx context app |> Async.RunSynchronously
            match res with
            | Some _ -> Task.CompletedTask
            | None -> base.Next.Invoke context

    [<Extension>]
    let UseSuave(app : Owin.IAppBuilder) =
        app.Use(typeof<SuaveMiddleware>)

主要作品被委托给withCtx,该IOwinContext尝试在WebPartSuaveMiddleware的情况下完成请求。它主要通过在Suave和OWIN上下文和相关实体之间来回转换来实现。 请注意,此代码是 PoC (概念验证),不适合生产。 如果Suave无法满足请求,则using MySuave; using Owin; namespace Main { using System.Web.Http; public class Startup { public static void Configuration(IAppBuilder appBuilder) { appBuilder.UseSuave(); var config = new HttpConfiguration(); config.MapHttpAttributeRoutes(); appBuilder.UseWebApi(config); } } } 转发请求到下一个中​​间件。

使用C#很容易:

namespace Main.Example
{
    using System.Web.Http;

    [RoutePrefix("api")]
    public class ExampleController : ApiController
    {
        [HttpGet, Route("")]
        public string Index()
        {
            return "Hello World";
        }
    }
}

给定的

http://localhost:9000/hello

这两个网址都有效:

http://localhost:9000/api

  

你好GET

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Hello World</string>

UFT-8

1 至少我不知道。我很高兴被证明是错的。