Я нахожусь в процессе изучения WebSharper, и я изо всех сил пытаюсь заставить некоторую часть моей логики работать на стороне клиента.
У меня есть несколько серверных объектов с иерархией наследования, которые мне нужно предоставить клиентской стороне. Они имеют дело с созданием различных частей страницы в виде фрагментов документа, но на клиенте.
[<JavaScriptExport>]
type [<AbstractClass>] A() =
abstract member Doc: Map<string, A> -> Doc
...
[<JavaScriptExport>]
type [<AbstractClass>] B() =
inherit A()
[<JavaScriptExport>]
type C() =
inherit B()
Запись обновлена , см. history для более старой версии.
В моем коде на стороне сервера У меня есть карта, связывающая каждый объект с заданным именем (как в шаблоне разработки стратегии):
let mutable objectMap : Map<string, A> = Map.empty
В какой-то момент карта заполняется данными. Это происходит один раз только на этапе инициализации приложения, но является результатом серверной логики на стороне сервера.
Теперь мне нужно использовать эти объекты только на стороне клиента, как в чрезмерно упрощенном фрагменте ниже:
[<JavaScriptExport>]
type C() =
inherit B() // or inherit A()
override this.Doc map =
div [] [ map.["innerDoc"].Doc(map)
На стороне сервера у меня будет:
module ServerSide =
let Main ctx endpoint ... =
// this is the mapping that is being generated on the server, derived somehow from the `objectMap ` above:
let serverMap : Map<string, something> = ...
let document =
[
div [ on.afterRender(fun _ -> ClientCode.fromServerMap(serverMap));][client <@ ClientCode.getDoc("someDoc") @>]
] |> Doc.Concat
Page.Content document
Модуль ClientCode
будет скомпилирован в JS и будет выглядеть так:
[<JavaScript>]
moduel ClientCode =
let _map : Var<Map<string, A>> = Var.Create <| Map.empty
let fromServerMap (serverMap : something) =
let clientMap : Map<string, A> = // TODO: get the information from server map
_map.Set clientMap
let getDoc (docName : string) =
_map.View.Map(fun m -> m.[docName].Doc(m))
|> Doc.EmbedView
До сих пор я узнал, что простой возврат карты через Rpc
во время afterRender
не будет работать - либо возвращаются общие объекты JS, либо я получаю сериализацию ошибка. Похоже, что это ожидаемое поведение для удаленного взаимодействия WebSharper и взаимодействия между сервером и клиникой.
Я знаю, что мог бы просто реализовать свои ClientModule.obtainObject
, жестко закодировав A
экземпляров внутри своей карты , и это сработает , если я это сделаю, но мне нужно избегать этой части. Модуль, который я разрабатываю, не должен знать точное отображение или реализацию типов, унаследованных от A
(например, B
и C
), а также с какими именами они были связаны.
Какие еще подходы мне нужно использовать для передачи информации от серверной карты объектов клиенту? Может быть, использовать что-то вроде Quotation.Expr<A>
в моем коде?
Обновление 1: Мне не обязательно создавать экземпляры объектов на сервере. Может быть, есть способ отправить информацию сопоставления клиенту и позволить ему каким-либо образом создать экземпляр?
Обновление 2: Вот репозиторий github с простым представлением того, что у меня работает до сих пор
Обновление 3: Альтернативным подходом было бы сохранить на сервере маппинг, который бы использовал имя моего типа объекта вместо его экземпляра (Map<string, string>
). Теперь, если мой клиентский код видит ClientAode.C
того, что является полным именем типа, возможно ли вызвать конструктор по умолчанию этого типа полностью из JavaScript?