5

C# で記述された既存の owin アプリケーションがあり、ミドルウェアとして適切なアプリケーションをマウントしたいと考えていますが、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.ofAppFuncまたはの組み合わせだと思いますOwinApp.ofMidFuncが、私は一生、それがどうあるべきかを理解できません。

4

1 に答える 1

5

簡単な魔法はありません。1 ofAppFuncであり、OWIN コンポーネントから sofMidFuncを作成するためにここにWebPartあります。つまり、OWIN -> Suave ですが、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要求を満たすことを試みます。これは主に、Suave と OWIN のコンテキストと関連するエンティティとの間で相互に変換することによって行われます。このコードはPoC (概念実証) であり、本番環境には適していないことに注意してください。Suave がリクエストを実行できない場合、次のミドルウェアにリクエストを転送します。IOwinContextWebPartSuaveMiddleware

C# からの使用は簡単です。

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);
        }
    }
}

与えられた

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

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

どちらの URL も機能します。

http://localhost:9000/hello

こんにちはGET

http://localhost:9000/api

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

1少なくとも私が知っているものはありません。私が間違っていることが証明されてうれしいです。

于 2016-08-14T19:05:48.883 に答える