Fable.Remoting adalah lapisan komunikasi RPC untuk aplikasi Fable dan .NET, yang mengabstraksi Http dan Json dan memungkinkan Anda memikirkan interaksi klien-server Anda hanya dalam kaitannya dengan fungsi stateless murni yang diperiksa secara statis pada waktu kompilasi:
Antarmuka ini adalah tipe rekaman yang setiap kolomnya adalah Async<'T>
atau fungsi yang mengembalikan Async<'T>
ketik IGreetingApi = { salam : string -> Async<string>}
biarkan salamApi = { sapa = nama menyenangkan ->async { biarkan salam = sprintf "Halo, %s" nama kembalikan salam}}// Paparkan implementasi sebagai layanan HTTP webApp = Jarak jauh.createApi() |> Remoting.fromValue salamApi
// dapatkan proxy yang diketik untuk servicelet salamApi = Jarak jauh.createApi() |> Remoting.buildProxy<IGreetingApi>// Mulai menggunakan serviceasync { membiarkan! pesan = salamApi.sapa "Dunia" printfn pesan "%s" // Halo, Dunia}
Itu saja, tanpa HTTP, tanpa JSON dan semuanya aman untuk tipe.
SAFE-TodoList Aplikasi daftar Todo full-stack sederhana (pemula)
tabula-rasa platform blogging dunia nyata (menengah)
Sistem Pemesanan Kelas Yobo Yoga diimplementasikan dengan Sumber Acara (lanjutan)
Pustaka berjalan di mana saja di backend: Sebagai Suave WebPart
, sebagai Giraffe/Saturn HttpHandler
atau kerangka kerja lainnya sebagai middleware Asp.NET Core. Klien dapat berupa aplikasi Fable atau .NET.
"Fable.Remoting memecahkan masalah kuno dalam menjaga kode front-end Anda tetap sinkron dengan kode backend Anda pada waktu kompilasi, dan dalam bahasa yang menyenangkan untuk digunakan seperti F#" - David Falkner
Gunakan templat SAFE Sederhana di mana Fable.Remoting sudah disiapkan dan siap digunakan
Perpustakaan | Versi |
---|---|
Fabel.Remoting.MsgPack | |
Fabel.Remoting.Klien | |
Fabel.Remoting.Json | |
Fabel.Remoting.Server | |
Fabel.Remoting.Ramah tamah | |
Fabel.Remoting.Jerapah | |
Fabel.Remoting.AspNetCore | |
Fabel.Remoting.DotnetClient | |
Fable.Remoting.AzureFunctions.Worker | |
Fabel.Remoting.AwsLambda |
Buat aplikasi konsol F# baru:
dotnet new console -lang F#
Tentukan tipe yang ingin Anda bagikan antara klien dan server:
// SharedTypes.fsmodule SharedTypestype Student = {Name : stringAge : int}// Spesifikasi bersama antara Server dan Clienttype IStudentApi = {studentByName : string -> Async<Student option>allStudents : unit -> Async<list<Student>>}
Tipe IStudentApi
sangat penting, ini adalah spesifikasi protokol antara server dan klien Anda. Fable.Remoting
mengharapkan tipe seperti itu hanya memiliki fungsi yang mengembalikan Async
pada hasil akhir:
Async<A>A -> Async<B>A -> B -> Async<C>// dll...
Cobalah untuk meletakkan tipe seperti itu di file terpisah untuk mereferensikan file-file ini nanti dari Klien
Kemudian berikan implementasi untuk IStudentApi
di server:
buka SharedTypeslet getStudents() = async {kembali [{ Nama = "Mike"; Umur = 23; }{ Nama = "Yohanes"; Umur = 22; }{ Nama = "Diana"; Umur = 22; }] }biarkan cariStudentByName nama = async {biarkan! siswa = getStudents()biarkan siswa = List.tryFind (siswa menyenangkan -> siswa.Nama = nama) siswakembali siswa }biarkan siswaApi : IStudentApi = {studentByName = findStudentByName semuaSiswa = getSiswa}
Sekarang kita memiliki implementasi studentApi
, Anda dapat mengeksposnya sebagai layanan web dari kerangka web yang berbeda. Kita mulai dengan ramah tamah
Instal perpustakaan dari Nuget menggunakan Paket:
paket add Fable.Remoting.Suave --project /path/to/Project.fsproj
Buat WebPart dari nilai studentApi
buka Suaveopen Fable.Remoting.Serveropen Fable.Remoting.Suavelet webApp : WebPart =Remoting.createApi()|> Remoting.fromValue studentApi|> Remoting.buildWebPart// mulai server webstartWebServer defaultConfig webApp
Ya, sesederhana itu. Anda dapat menganggap nilai webApp
seolah-olah itu adalah kode semu berikut:
biarkan webApp = memilih [ POST >=> jalur "/IStudentApi/studentByName" >=> (* deserialisasi isi permintaan (dari json) *) >=> (* panggil studentApi.getStudentByName dengan input yang dideserialisasi *) >=> (* berikan klien output kembali berseri (ke json) *) // rute lain ]
Anda dapat mengaktifkan logging diagnostik dari Fable.Remoting.Server (disarankan) untuk melihat bagaimana perpustakaan melakukan keajaiban di balik layar :)
biarkan webApp =Remoting.createApi()|> Remoting.fromValue studentApi|> Remoting.withDiagnosticsLogger (printfn "%s")|> Remoting.buildWebPart
Instal paket dari Nuget menggunakan paket
paket add Fable.Remoting.AspNetCore --project /path/to/Project.fsproj
Sekarang Anda dapat mengonfigurasi pengendali jarak jauh Anda sebagai middleware AspNetCore
biarkan webApp =Remoting.createApi()|> Remoting.fromValue studentApilet mengkonfigurasiApp (aplikasi : IApplicationBuilder) =// Tambahkan pengendali Remoting ke aplikasi pipeline ASP.NET Core.UseRemoting webApp[<EntryPoint>]biarkan main _ =WebHostBuilder().UseKestrel ().Konfigurasi(Aksi<IApplicationBuilder> konfigurasikanApp).Build().Run()0
Anda dapat mengikuti bagian Suave hingga instalasi perpustakaan, yang akan menjadi:
paket add Fable.Remoting.Giraffe --project /path/to/Project.fsproj
Sekarang, alih-alih WebPart, dengan membuka namespace Fable.Remoting.Giraffe
, Anda akan mendapatkan HttpHandler dari server
nilai :
buka Giraffeopen Fable.Remoting.Serveropen Fable.Remoting.Giraffelet webApp : HttpHandler =Remoting.createApi()|> Remoting.fromValue studentApi|> Remoting.buildHttpHandlerletconfigureApp (app : IApplicationBuilder) =// Tambahkan Giraffe ke aplikasi pipeline ASP.NET Core .UseGiraffe webApplet mengkonfigurasiLayanan (layanan : IServiceCollection) =// Tambahkan Giraffe dependenciesservices.AddGiraffe() |> abaikan[<EntryPoint>]biarkan main _ =WebHostBuilder().UseKestrel().Configure(Action<IApplicationBuilder> ConfigureApp).ConfigureServices(configureServices).Build() .Jalankan()0
Anda dapat menggunakan webApp
yang sama yang dihasilkan oleh perpustakaan Giraffe.
buka Saturnopen Fable.Remoting.Serveropen Fable.Remoting.Giraffelet webApp : HttpHandler =Remoting.createApi()|> Remoting.fromValue studentApi|> Remoting.buildHttpHandlerlet app = application {url "http://127.0.0.1:8083/"use_router webApp}menjalankan aplikasi
Untuk menggunakan Azure Functions dalam mode terisolasi dengan HttpTrigger kustom sebagai server jarak jauh tanpa server, cukup instal:
dotnet add package Fable.Remoting.AzureFunctions.Worker
atau menggunakan paket
paket add Fable.Remoting.AzureFunctions.Worker --project /path/to/Project.fsproj
Karena Azure Functions tidak mengetahui apa pun tentang HttpHandler, kita perlu menggunakan objek HttpRequestData
dan HttpResponseData
bawaan. Untungnya kami memiliki fungsi Remoting.buildRequestHandler
dan HttpResponseData.fromRequestHandler
untuk menyelamatkan:
buka Fable.Remoting.Serveropen Fable.Remoting.AzureFunctions.Workeropen Microsoft.Azure.Functions.Workeropen Microsoft.Azure.Functions.Worker.Httpopen Microsoft.Extensions.Loggingtype Functions(log:ILogger<Functions>) =[<Function("Index ")>]anggota _.Index ([<HttpTrigger(AuthorizationLevel.Anonymous, Route = "{*any}")>] req: HttpRequestData, ctx: FunctionContext) =Remoting.createApi()|> Remoting.withRouteBuilder FunctionsRouteBuilder.apiPrefix|> Remoting.fromValue myImplementation|> Jarak jauh.buildRequestHandler|> Persyaratan HttpResponseData.fromRequestHandler
Tentu saja, memiliki satu implementasi per Aplikasi Fungsi tidaklah ideal, jadi HttpResponseData.fromRequestHandlers
siap membantu:
ketik Fungsi(log:ILogger<Functions>) =[<Function("Index")>]anggota _.Index ([<HttpTrigger(AuthorizationLevel.Anonymous, Route = "{*any}")>] req: HttpRequestData, ctx : FunctionContext) =biarkan handlerOne =Remoting.createApi()|> Remoting.withRouteBuilder FunctionsRouteBuilder.apiPrefix|> Remoting.fromValue myImplementationOne|> Remoting.buildRequestHandler biarkan handlerTwo =Remoting.createApi()|> Remoting.withRouteBuilder FunctionsRouteBuilder.apiPrefix|> Remoting.fromValue myImplementationTwo|> Remoting.buildRequestHandler [ handlerOne; handlerTwo ] |> Permintaan HttpResponseData.fromRequestHandlers
Instal Fable.Remoting.Client
dari nuget menggunakan Paket:
paket add Fable.Remoting.Client --project /path/to/Project.fsproj
Referensikan tipe yang dibagikan ke proyek klien Anda
<Compile Include="path/to/SharedTypes.fs" />
Mulai menggunakan perpustakaan:
buka Fable.Remoting.Clientopen SharedTypes// studentApi : IStudentApilet studentApi =Remoting.createApi()|> Remoting.buildProxy<IStudentApi>async { // siswa : Siswa[] membiarkan! siswa = pelajarApi.allStudents() untuk pelajar di pelajar lakukan// pelajar : Studentprintfn "Siswa %s berusia %d tahun" pelajar.Nama pelajar.Umur}|> Async.StartImmediate
Terakhir, saat Anda menggunakan webpack-dev-server
, Anda harus mengubah konfigurasi dari ini:
server pengembang: { basis konten: tekad('./publik'), pelabuhan: 8080}
untuk ini:
server pengembang: { basis konten: tekad('./publik'), pelabuhan: 8080, proxy: {'/*': { // beri tahu webpack-dev-server untuk merutekan ulang semua permintaan dari klien ke server target: "http://localhost:5000",// dengan asumsi server backend dihosting di port 5000 selama perubahan pengembangan Asal: benar}}
Itu saja!
Anda juga dapat menggunakan fungsionalitas klien dalam proyek non-fabel, seperti konsol, desktop, atau aplikasi seluler.
Instal Fable.Remoting.DotnetClient
dari nuget menggunakan Paket:
paket add Fable.Remoting.DotnetClient --project /path/to/Project.fsproj
Referensikan tipe bersama dalam proyek klien Anda
<Compile Include="path/to/SharedTypes.fs" />
Mulai menggunakan perpustakaan:
buka Fable.Remoting.DotnetClientopen SharedTypes// studentApi : IStudentApilet studentApi = Remoting.createApi "http://localhost:8085" |> Remoting.buildProxy<IStudentApi>async { // siswa : Siswa[] membiarkan! siswa = pelajarApi.allStudents() untuk pelajar di pelajar lakukan// pelajar : Studentprintfn "Siswa %s berusia %d tahun" pelajar.Nama pelajar.Umur}|> Async.StartImmediate
Perhatikan di sini, tidak seperti klien Fable, Anda perlu memberikan Url dasar backend karena klien dotnet akan diterapkan secara terpisah dari backend.
Tambahkan fungsi bidang catatan lain ke IStudentApi
Terapkan fungsi itu
Mulai ulang server dan klien
Selesai! Anda sekarang dapat menggunakan fungsi itu dari klien juga.
Lihat artikel berikut jika Anda tertarik pada bagaimana perpustakaan ini diimplementasikan (agak ketinggalan jaman tetapi memberi Anda gambaran umum mekanismenya) Komunikasi Klien-Server yang Diketik Secara Statis dengan F#: Bukti Konsep