假设我们有这个 Web 服务器来处理请求:
let webApp = scope {
get "/api/zoo/animals/" (getAllAnimals())
getf "/api/zoo/animals/%s" getAnimalInfo
}
Run Code Online (Sandbox Code Playgroud)
现在,如果我想在 url 查询中有一个参数,例如过滤结果,该怎么办?
http://localhost:8080/api/zoo/animals?type=mammals
Run Code Online (Sandbox Code Playgroud)
这不会做任何事情:
getf "/api/zoo/animals?type=%s" getAnimalsByType
Run Code Online (Sandbox Code Playgroud) 我正在尝试使用身份服务来管理我的应用程序的登录。我有以下
let configureServices (services : IServiceCollection) =
// Configure InMemory Db for sample application
services.AddDbContext<IdentityDbContext<IdentityUser>>(
fun options ->
options.UseInMemoryDatabase("NameOfDatabase") |> ignore
) |> ignore
Run Code Online (Sandbox Code Playgroud)
但是它使用内存数据库。我想保留用户注册信息,并且我有 postgresql 设置并想使用该数据库来保留信息。我在 settings.json 文件中有 connectionString 信息。我想把上面的函数改成这样:
let configureServices (services : IServiceCollection) =
// Configure InMemory Db for sample application
services.AddDbContext<IdentityDbContext<IdentityUser>>(
fun options ->
let config = ctx.GetService<IConfiguration>()
let connString = config.Item("connectionString")
options.UseNpgsql(connString) |> ignore
) |> ignore
Run Code Online (Sandbox Code Playgroud)
但问题出在 configureServices 函数中,我无权访问处理应用程序配置的 Httpcontext(由上面的 ctx 表示)。我该怎么做呢?基本上我想从我的 configureServices 函数中的 settings.json 文件中获取 connectionString 字段的值。
我正在设置一个简单的Giraffe应用程序,其中包含一个或两个端点和一个 SignalR 集线器。我所拥有的是这样的:
type JsonBlob = JsonProvider<"Blob.json">
type Message =
| GetBlobs of AsyncReplyChannel<JsonBlob.Root list>
| PostBlob of JsonBlob.Root
type JsonBlobHub(agent : MailboxProcessor<Message>) =
inherit Hub()
member self.RespondToClient() =
let blobs = agent.PostAndReply(GetBlobs)
self.Clients.All.SendAsync("ReceiveBlobList", blobs)
let agentFactory(serviceProvider : IServiceProvider) =
let thing = serviceProvider.GetService<Thing>()
MailboxProcessor.Start(fun (inbox : MailboxProcessor<Message>) ->
/* loop implementation */
)
// other stuff
let configureApp (app : IApplicationBuilder) =
app.UseSignalR(fun routes -> routes.MapHub<JsonBlobHub>(PathString "/blobhub")) |> ignore
app.UseGiraffe webApp // webApp defined elsewhere, not important …
Run Code Online (Sandbox Code Playgroud) 假设我有一个处理程序从请求中计算一些数据(例如用户 ID),并且该数据由应用程序中的后续代码使用。
我可以想到两种传递这些数据的方法:
1. 变异ctx.Items
集合
这看起来像这样:
let authenticate : HttpHandler =
fun (next : HttpFunc) (ctx : HttpContext) ->
task {
printfn "Authenticating... "
let userID = Guid.NewGuid () // Dummy
printfn "Authenticated as %A" userID
ctx.Items.["userID"] <- userID
return! next ctx
}
Run Code Online (Sandbox Code Playgroud)
然后要获取数据,只需执行以下操作:
let showUser : HttpHandler =
fun (next : HttpFunc) (ctx : HttpContext) ->
task {
let userID = ctx.Items.["userID"] :?> Guid
return! text (sprintf "You are authenticated as %A. " userID) next ctx
} …
Run Code Online (Sandbox Code Playgroud) 您将如何从configureServices
Giraffe-FSharp 中的方法内部访问配置?
这是SAFE 模板通过dotnet new SAFE -lang F# --server giraffe
以下方式创建的 Giraffe 设置的节选部分:
let configureServices (services : IServiceCollection) =
services.AddCors() |> ignore
services.AddGiraffe() |> ignore
// Want to access configuration here.
[<EntryPoint>]
let main _ =
let contentRoot = Directory.GetCurrentDirectory()
let webRoot = Path.Combine(contentRoot, "WebRoot")
WebHostBuilder()
.UseKestrel()
.UseContentRoot(contentRoot)
.UseIISIntegration()
.UseWebRoot(webRoot)
.Configure(Action<IApplicationBuilder> configureApp)
.ConfigureAppConfiguration(Action<WebHostBuilderContext, IConfigurationBuilder> configureAppConfig)
.ConfigureServices(configureServices)
.ConfigureLogging(configureLogging)
.Build()
.Run()
0
Run Code Online (Sandbox Code Playgroud) 我创建了一个辅助函数,用于从我的 Giraffe 项目返回 Thoth.Json 样式的 json,该函数接受Result<'a,'b>
并返回 JSON。
let json result next (ctx: HttpContext) =
match result with
| Ok result ->
(setHttpHeader "Content-Type" "application/json" >=>
setBodyFromString (Encode.Auto.toString (0, result))) next ctx
| Error e -> ...
Run Code Online (Sandbox Code Playgroud)
这工作正常,直到我返回Ok ()
,它编译并且应该完全有效。
然而,Thoth.Json 不太喜欢它:
Cannot generate auto encoder for Microsoft.FSharp.Core.Unit. Please pass an extra encoder.
我怎样才能检查是否result
是一个unit
或使自动编码器句柄unit
?
由于某些原因,services.AddSingleton<IHostedService, CommandConsumer> |> ignore
在let configureServices (services : IServiceCollection)
调试F#Giraffe应用程序时跳过了该行
。
令人沮丧的是该程序可以编译,因此我希望该程序能够在该行的断点处停止,但事实并非如此。
奇怪的是,如果我使用扩展方法的完整名称空间,则断点可以工作...
Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<IHostedService, CommandConsumer>(services) |> ignore
中的源代码Program.fs
:
module Rm.Accounting.Workflows.Api.App
open System
open System.Threading
open System.Threading.Tasks
open System.IO
open Microsoft.AspNetCore.Builder
open Microsoft.AspNetCore.Hosting
open Microsoft.Extensions.Logging
open Microsoft.Extensions.DependencyInjection
open Giraffe
open Microsoft.AspNetCore.Http
open Microsoft.Extensions.Hosting
type CommandConsumer()=
inherit BackgroundService()
override __.ExecuteAsync(cancellationToken : CancellationToken) =
Task.CompletedTask
let webApp = choose [
GET >=>
choose [
route "/" >=> redirectTo false "/health"
]
setStatusCode 404 >=> text "Not Found" ]
let …
Run Code Online (Sandbox Code Playgroud)