在 Owin 应用程序中安装 Suave
Mounting Suave in an Owin application
我有一个用 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.ofAppFunc
或 OwinApp.ofMidFunc
的组合,但我想不出它应该是什么。
没有简单的魔法。1 ofAppFunc
和 ofMidFunc
用于从 OWIN 组件创建 WebPart
s,即 OWIN -> Suave,而你想要 Suave -> OWIN。
以下内容适用于您的 'application',并作为示例使其正常工作:
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
和 WebPart
的请求。它主要通过在 Suave 和 OWIN 上下文及相关实体之间来回转换来实现。
请注意,此代码是 PoC(概念验证)并且不适合生产。
如果 Suave 无法满足请求,SuaveMiddleware
将请求转发到下一个中间件。
然后从 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
Hello GET
http://localhost:9000/api
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Hello World</string>
1 至少 none 我知道的。我很高兴被证明是错误的。
我有一个用 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.ofAppFunc
或 OwinApp.ofMidFunc
的组合,但我想不出它应该是什么。
没有简单的魔法。1 ofAppFunc
和 ofMidFunc
用于从 OWIN 组件创建 WebPart
s,即 OWIN -> Suave,而你想要 Suave -> OWIN。
以下内容适用于您的 'application',并作为示例使其正常工作:
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
和 WebPart
的请求。它主要通过在 Suave 和 OWIN 上下文及相关实体之间来回转换来实现。
请注意,此代码是 PoC(概念验证)并且不适合生产。
如果 Suave 无法满足请求,SuaveMiddleware
将请求转发到下一个中间件。
然后从 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
Hello GET
http://localhost:9000/api
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Hello World</string>
1 至少 none 我知道的。我很高兴被证明是错误的。