Fable.Remoting 是 Fable 和 .NET 應用程式的 RPC 通訊層,它抽象化了 Http 和 Json,讓您僅根據在編譯時靜態檢查的純無狀態函數來考慮客戶端-伺服器互動:
此介面是一種記錄類型,其中每個欄位都是Async<'T>
或傳回Async<'T>
的函數
類型 IGreetingApi = { 問候:字串->異步<字串>}
讓greetingApi = { greet = fun name ->async { letgreeting = sprintf "Hello, %s" name returngreeting}}// 將實作公開為 HTTP servicelet webApp = 遠端處理.createApi() |> Remoting.fromValuegreetingApi
// 取得 serviceletgreetingApi 的類型化代理 = 遠端處理.createApi() |> Remoting.buildProxy<IGreetingApi>// 開始使用 serviceasync { 讓!訊息=greetingApi.greet“世界” printfn "%s" 訊息 // 你好,世界}
就是這樣,沒有 HTTP,沒有 JSON,而且都是型別安全的。
SAFE-TodoList 一個簡單的全端Todo列表應用程式(初學者)
tabula-rasa 一個真實世界的部落格平台(中級)
使用事件採購實現的 Yobo 瑜珈課程預訂系統(高級)
該庫在後端的任何地方運行:作為 Suave WebPart
、作為 Giraffe/Saturn HttpHandler
或作為 Asp.NET Core 中間件的任何其他框架。客戶端可以是 Fable 或 .NET 應用程式。
「Fable.Remoting 解決了一個古老的問題,即在編譯時保持前端程式碼與後端程式碼同步,並且使用像 F# 一樣令人愉快的語言」- David Falkner
使用 SAFE 簡化模板,其中 Fable.Remoting 已設定並準備就緒
圖書館 | 版本 |
---|---|
神鬼寓言.Remoting.MsgPack | |
寓言.遠端.客戶端 | |
寓言.Remoting.Json | |
神鬼寓言遠端伺服器 | |
寓言.遠程.Suave | |
寓言.遠程.長頸鹿 | |
神鬼寓言.Remoting.AspNetCore | |
Fable.Remoting.DotnetClient | |
Fable.Remoting.AzureFunctions.Worker | |
神鬼寓言.Remoting.AwsLambda |
建立一個新的 F# 控制台應用程式:
dotnet new console -lang F#
定義要在客戶端和伺服器之間共用的類型:
// SharedTypes.fsmodule SharedTypestype Student = {Name : stringAge : int}// 伺服器與客戶端之間的共用規範 type IStudentApi = {studentByName : string -> Async<Student option>allStudents : unit -<listd >>}
IStudentApi
類型非常重要,這是伺服器和客戶端之間協定的規範。 Fable.Remoting
期望此類類型僅具有在最終結果上傳回Async
函數:
Async<A>A -> Async<B>A -> B -> Async<C> // 等等...
嘗試將此類類型放入單獨的文件中,以便稍後從客戶端引用這些文件
然後在伺服器上提供IStudentApi
的實作:
打開 SharedTypeslet getStudents() = 異步{返回[{名稱=“邁克”; 年齡=23; } 名字=「約翰」; 年齡=22; } 名字=「戴安娜」;年齡=22; }] }讓 findStudentByName 名稱 = 異步{讓!學生 = getStudents()let 學生 = List.tryFind (fun 學生 -> 學生.Name = 姓名) 學生回傳學生 }let StudentApi : IStudentApi = {studentByName = findStudentByName 所有學生 = getStudents}
現在我們已經實作了studentApi
,您可以將其公開為來自不同 Web 框架的 Web 服務。我們從溫柔開始
使用 Paket 從 Nuget 安裝庫:
paket add Fable.Remoting.Suave --project /path/to/Project.fsproj
從值studentApi
建立 WebPart
open Suaveopen Fable.Remoting.Serveropen Fable.Remoting.Suavelet webApp : WebPart =Remoting.createApi()|> Remoting.fromValue StudentApi|> Remoting.buildWebPart//啟動WebstartWebServer defaultConfig 伺服器
是的,就是這麼簡單。您可以將webApp
值視為偽代碼中的以下內容:
讓網頁應用= 選擇 [ POST >=> 路徑“/IStudentApi/studentByName” >=> (* 反序列化請求正文(來自 json)*) >=> (* 使用反序列化輸入呼叫 StudentApi.getStudentByName *) >=> (* 提供客戶端序列化的輸出(轉為 json)*) // 其他路線 ]
您可以從 Fable.Remoting.Server(建議)啟用診斷日誌記錄,以查看該庫如何在幕後發揮它的魔力:)
讓 webApp =Remoting.createApi()|> Remoting.fromValue StudentApi|> Remoting.withDiagnosticsLogger (printfn "%s")|> Remoting.buildWebPart
使用 paket 從 Nuget 安裝軟體包
paket add Fable.Remoting.AspNetCore --project /path/to/Project.fsproj
現在您可以將遠端處理程序設定為 AspNetCore 中介軟體
let webApp =Remoting.createApi()|> Remoting.fromValue StudentApilet configureApp (app : IApplicationBuilder) =// 將Remoting 處理程序新增至ASP.NET Core 管道app.UseRemoting webApp[<EntryPoint>]let main _Web =HostBuilder() .UseKestrel ().Configure(Action<IApplicationBuilder> configureApp).Build().Run()0
您可以按照 Suave 部分進行庫安裝,它將變成:
paket add Fable.Remoting.Giraffe --project /path/to/Project.fsproj
現在,透過開啟Fable.Remoting.Giraffe
命名空間,您將從值server
取得 HttpHandler,而不是 WebPart:
open Giraffeopen Fable.Remoting.Serveropen Fable.Remoting.Giraffelet webApp : HttpHandler =Remoting.createApi()|> Remoting.fromValue StudentApi|> Remoting.buildHttpHandlerlet configureApp( .UseGiraffe webApplet configureServices (services : IServiceCollection) =// 新增Giraffe依賴項services.AddGiraffe() |>ignore[<EntryPoint>]let main _ =WebHostBuilder().UseKestrel().Configure(Action<IlicationBuilder.UseKestrel().Configure(Action<IlicationBuilder). ConfigureServices(設定服務).Build().Run()0
您可以使用 Giraffe 庫產生的相同webApp
。
open Saturnopen Fable.Remoting.Serveropen Fable.Remoting.Giraffelet webApp : HttpHandler =Remoting.createApi()|> Remoting.fromValue StudentApi|> Remoting.buildHttpHandlerlet app = appliValue StudentApi|> Remoting.buildHttpHandlerlet app = appliValue StudentApi|> Remoting.buildHttpHandlerlet app = appliValue StudentApi|> Remoting.buildHttpHandlerlet app = appliValue StudentApi|127. webApp}運行應用程式
若要在隔離模式下使用 Azure Functions 並將自訂 HttpTrigger 作為無伺服器遠端處理伺服器,只需安裝:
dotnet add package Fable.Remoting.AzureFunctions.Worker
或使用包
paket add Fable.Remoting.AzureFunctions.Worker --project /path/to/Project.fsproj
由於 Azure Functions 對 HttpHandler 一無所知,因此我們需要使用內建的HttpRequestData
和HttpResponseData
物件。幸運的是,我們有Remoting.buildRequestHandler
和HttpResponseData.fromRequestHandler
函式來救援:
open Fable.Remoting.Serveropen Fable.Remoting.AzureFunctions.Workeropen Microsoft.Azure.Functions.Workeropen Microsoft.Azure.Functions.Worker.Httpopen Microsoft.Extensions.Loggingtype Functions(log:ILogger<Functions. ")>]member _.Index ([<HttpTrigger(AuthorizationLevel.Anonymous, Route = "{*any}")>] req: HttpRequestData, ctx: FunctionContext) =Remoting.createApi()|> Remoting.withRouteBuilder F. |> Remoting.fromValue myImplementation|> Remoting.buildRequestHandler|> HttpResponseData.fromRequestHandler req
當然,每個 Function App 都有一個實作並不理想,因此HttpResponseData.fromRequestHandlers
可以解決這個問題:
類型 Functions(log:ILogger<Functions>) =[<Function("Index")>]member _.Index ([<HttpTrigger(AuthorizationLevel.Anonymous, Route = "{*any}")>] req: HttpRequestData, ctx : FunctionContext) =let handlerOne =Remoting.createApi()|> Remoting.withRouteBuilder FunctionsRouteBuilder.apiPrefix|> Remoting.fromValue myImplementationOne|> Remoting.buildRequestHandler 讓handlerTwo =Remoting.createApi.處理.fromValue myImplementationTwo|> Remoting.buildRequestHandler [ handlerOne; handlerTwo ] |> HttpResponseData.fromRequestHandlers 要求
使用 Paket 從 nuget 安裝Fable.Remoting.Client
:
paket add Fable.Remoting.Client --project /path/to/Project.fsproj
將共享類型引用到您的客戶端項目
<Compile Include="path/to/SharedTypes.fs" />
開始使用該庫:
open Fable.Remoting.Clientopen SharedTypes// StudentApi : IStudentApilet StudentApi =Remoting.createApi()|> Remoting.buildProxy<IStudentApi>async { // 學生:學生[] 讓!學生 = StudentApi.allStudents() for Student in Students do// Student : Studentprintfn "學生 %s 已 %d 歲" Student.Name Student.Age}|> Async.StartImmediate
最後,當您使用webpack-dev-server
時,您必須變更配置:
開發伺服器:{ contentBase: 解析('./public'), 埠:8080}
對此:
開發伺服器:{ contentBase: 解析('./public'), 端口:8080, proxy: {'/*': { // 告訴 webpack-dev-server 將所有從客戶端的請求重新路由到伺服器 target: "http://localhost:5000",// 假設後端伺服器託管在連接埠上開發期間5000 次更改來源:true}}
就是這樣!
您也可以在非寓言專案中使用用戶端功能,例如控制台、桌面或行動應用程式。
使用 Paket 從 nuget 安裝Fable.Remoting.DotnetClient
:
paket add Fable.Remoting.DotnetClient --project /path/to/Project.fsproj
引用客戶端專案中的共用類型
<Compile Include="path/to/SharedTypes.fs" />
開始使用該庫:
open Fable.Remoting.DotnetClientopen SharedTypes// StudentApi : IStudentApilet StudentApi = Remoting.createApi“http://localhost:8085” |> Remoting.buildProxy<IStudentApi>async { // 學生:學生[] 讓!學生 = StudentApi.allStudents() for Student in Students do// Student : Studentprintfn "學生 %s 已 %d 歲" Student.Name Student.Age}|> Async.StartImmediate
請注意,與 Fable 用戶端不同,您需要提供後端的基本 Url,因為 dotnet 用戶端將與後端分開部署。
在IStudentApi
新增另一個記錄欄位函數
實現該功能
重啟伺服器和客戶端
完畢!現在您也可以從客戶端使用該功能。
如果您對該程式庫的實作方式感興趣,請參閱以下文章(有點過時,但為您提供了該機制的概述):使用 F# 進行靜態類型的客戶端-伺服器通訊:概念驗證