Git Product home page Git Product logo

fsbolero / bolero Goto Github PK

View Code? Open in Web Editor NEW
1.0K 53.0 53.0 4.01 MB

Bolero brings Blazor to F# developers with an easy to use Model-View-Update architecture, HTML combinators, hot reloaded templates, type-safe endpoints, advanced routing and remoting capabilities, and more.

Home Page: https://fsbolero.io

License: Apache License 2.0

F# 98.23% HTML 0.47% PowerShell 0.26% C# 1.03% CSS 0.01%
bolero blazor fsharp webassembly

bolero's People

Contributors

brikken avatar ctaggart avatar dedsec256 avatar dougq-puregym avatar granicz avatar ittennull avatar jand42 avatar jeremiahsanders avatar jooseppi12 avatar kojo12228 avatar laenas avatar landy avatar naartjie avatar psymm avatar rv-17 avatar shalokshalom avatar tarmil avatar xperiandri avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bolero's Issues

Add attr.classes

A function attr.classes : list<string> -> Attr would be helpful so that the user doesn't need to String.concat " " the classes they want to add to an element themselves.

It should be noted that since this always outputs exactly one attribute, it's perfectly fine to use conditional yield in the list passed to classes.

Question: should multiple calls to attr.classes on the same element be combined? I would say no: the latter call should override the former, making it consistent with every other attr.* function.

Slow response in the first 10 to 20 seconds

My Bolero 0.5 application - client with server - was very sluggish for perhaps 10 to 20 seconds after I started it in Debug in VS 2019. After that initial sluggishness the response was great.

I had noticed that this sluggishness had increased as I put more functionality into the client project. I suspected that perhaps the growing main.html was to blame, so I split it into two somewhat equally sized files. That helped tremendously. There is now still a slight delay when clicking menu items right after the browser comes up, but it is insignificant.

This issue was not a problem for me, since splitting main.html was something I wanted to do anyway. I am reporting the issue so that the behavior can be researched if need be. I attach the revision of the application as it was before splitting main.html.

TdWebServer-rev35.zip

The attached solution does not contain any business secrets in that particular revision, as I'm only at a stage where I research use of Bolero. Anyone is welcome to have a look, but please remove any references to its origins if snipping code, and do not post it elsewhere as is.

Templating: error when using a number bind as text hole

Example:

<input type="number" bind="${MyNumber}">
The value is ${MyNumber}

This fails without an error when trying to display, and with the following stack trace when setting from hot reload:

blazor.webassembly.js:1 Uncaught (in promise) Error: System.InvalidCastException: Specified cast is not valid.
  at Microsoft.JSInterop.DotNetDispatcher.InvokeSynchronously (System.String assemblyName, System.String methodIdentifier, System.Object targetInstance, System.String argsJson) <0x250dca8 + 0x001bc> in <af36ed9192be4a95b907125ccf0c1e59>:0 
  at Microsoft.JSInterop.DotNetDispatcher.BeginInvoke (System.String callId, System.String assemblyName, System.String methodIdentifier, System.Int64 dotNetObjectId, System.String argsJson) <0x261b980 + 0x00088> in <af36ed9192be4a95b907125ccf0c1e59>:0 
    at endInvokeDotNetFromJS (blazor.webassembly.js:1)
    at Object.invokeJSFromDotNet (blazor.webassembly.js:1)
    at _mono_wasm_invoke_js_marshalled (mono.js:1)
    at wasm-function[1450]:935
    at wasm-function[762]:25085
    at wasm-function[762]:23853
    at wasm-function[762]:23853
    at wasm-function[762]:23853
    at wasm-function[762]:24468
    at wasm-function[762]:24468

Next steps

I think the next step should be to make WebAssembly run in a Web Worker and keep the front end with WebSharper.UI. That would allow the integration of .Net libraries with the power of reactive UI.

Add prerelease tag to the version

NuGet doesn't like it when a release package depends on a prerelease package. So with the update to Blazor 3.0.0-preview5, we need to release Bolero itself with a prerelease tag. I propose -preview.

With nbgv, we'll have version 0.5.x-preview on master and 0.5.x-preview.githash on branches.

Bolero.Remoting.IRemoteService is not assignable from

I try to use Remoting but I get "Error: System.InvalidOperationException: constrained call: Bolero.Remoting.IRemoteService is not assignable from BitTorrentFileServer.Service.WebService"

This is my type:

namespace BitTorrentFileServer.Service

open BitTorrentFileServer.Data
open Bolero.Remoting

type WebService =
    {
        getFolders : unit -> Async<Folder>
    }
    
    interface IRemoteService with
        member this.BasePath = "/api"

I created a test C# program. In it I could cast it to IRemoteService like this:

var a = new BitTorrentFileServer.Service.WebService(null);

IRemoteService b = (IRemoteService)a;

Console.WriteLine(b.BasePath);

Routing: add supported types

Currently routing only supports union types with base types as case arguments. We should add support for more shapes:

  • Tuples
  • Records
  • Nested unions
  • Recursive unions

Routing: support query arguments

Add support for parsing query arguments in the router. Potential syntax (inspired by WebSharper's):

type Page =
    | [<EndPoint "/foo"; Query("x", "y")>]
      Foo of pathArg: string * x: int * y: option<string>

Bug with empty / conditionally rendering an element. Causes events to not be fired

I came across a bug in my app last night that was difficult to diagnose, and it ended up being because I was conditionally rendering an element which caused events to not trigger. I've tried to reproduce the bug in a new smaller app that does something similar, but was unsuccessful.

I have two data types, a Category / Child (in the example, City / Person). When I am rendering many of these Categories + Children in the same div [], I ran into issues with dispatching events only when some Categories did not have children AND a modal had been hidden, shown, and then hidden again. For some a few buttons tied to a category (not necessarily ones with no children) would stop firing its onclick event. It was consistently the 4th, 7th, and 8th elements (index 3, 6, 7). And again, this only happened when I had a modal div that wasn't rendered, was rendered, then wasn't again (hidden -> shown -> hidden), and not all categories had children. As soon as I made sure the children map wasn't empty in the View method, the issue disappeared.

My code was created from the Bolero-App template, and I switched to server side rendering. I have not tested in client side because my project relies on reading a file from disk

Here is some example code to give context to how I was rendering the table

module EmptyTest.Client.Main

open Elmish
open Bolero
open Bolero.Html

type City = { Id: int; Name: string }
type Person = { Id: int; CityId: int; Name: string }

type Model =
    {
        DisplayDiv: bool
        Cities: Map<int, City>
        People: Map<int, Person>
    }

let initModel =
    {
        DisplayDiv = false
        Cities = Map.ofList [ 
            (0, { Id = 0; Name = "Chicago" })
            (1, { Id = 1; Name = "New York"})
            (2, { Id = 2; Name = "Detroit" })
            (3, { Id = 3; Name = "Los Angelos" })
            (4, { Id = 4; Name = "Detroit"} )
        ]
        People = Map.ofList [ 
            (0, { Id = 0; CityId = 0; Name = "David" })
            (1, { Id = 1; CityId = 0; Name = "John" })
            (2, { Id = 2; CityId = 0; Name = "Samantha" })
            (3, { Id = 3; CityId = 2; Name = "Daniel" })
            (4, { Id = 4; CityId = 2; Name = "Ashley"})
        ]
    }

type Message =
    | ToggleDiv

let update message model =
    match message with
    | ToggleDiv -> { model with DisplayDiv = not(model.DisplayDiv) }

let view model dispatch =
    div [] [
        div [] [
            cond model.DisplayDiv <| function
            | true -> div [] [ div [] [ h3 [] [ text "Some content" ] ] ]
            | false -> empty
            table [] [
                forEach model.Cities (fun kv ->
                    let people = model.People |> Map.filter (fun id p -> p.CityId = kv.Key)
                    concat [
                        tr [ attr.style "background: lightgreen;" ] [
                            td [] [ textf "%d" kv.Key ]
                            td [] [ text kv.Value.Name ]
                            td [] [
                                // This buttons on.click stopped firing for certain categories only after a div had been added to the DOM (and removed? It was a modal so I'm not sure if both conditions are necessary)
                                button [ on.click (fun _ -> printfn "%d" kv.Key) ] [ text "Print Id" ]
                            ]
                        ]
                        forEach people (fun personKv ->
                            tr [] [
                                td [] [ textf "%d" personKv.Key ]
                                td [] [ text personKv.Value.Name ]
                                td [] [
                                    button [ on.click (fun _ -> dispatch ToggleDiv) ] [ text "Toggle Div" ]
                                ]
                            ]
                        )
                    ]
                )
            ]
        ]
    ]

type MyApp() =
    inherit ProgramComponent<Model, Message>()

    override this.Program =
        Program.mkSimple (fun _ -> initModel) update view

Here is the actual div code that was causing problems

module Modal =
    type Message<'childModel, 'childMessage> = | Confirm of 'childModel | Cancel | ChildMessage of 'childMessage
    type Model<'T> = { Display : bool; Title : string; Child : 'T }
    type Component<'T, 'childModel, 'childMessage when 'T :> ElmishComponent<'childModel, 'childMessage> and 'childModel :> IValidateable>() = 
        inherit ElmishComponent<Model<'childModel>, Message<'childModel, 'childMessage>>()

        override this.View model dispatch =
            cond model.Display <| function
            | true ->
                div [ attr.``class`` "modal" ] [
                    div [ attr.``class`` "modal-content" ] [
                        h3 [] [ text model.Title ]
                        ecomp<'T,_,_> model.Child (dispatch << ChildMessage)
                        p [] []
                        button [ 
                            attr.disabled (if isValid model.Child then null else "true")
                            on.click (fun _ -> dispatch <| Confirm model.Child)
                        ] [ text "Confirm" ]
                        button [ on.click (fun _ -> dispatch Cancel) ] [ text "Cancel" ]
                    ]
                ]
            | false ->
                empty

In the end I was able to fix this by replacing empty with div [ attr.style "display: none;" ] []. I'm not sure if I was using empty improperly here, or if it is a bug. In the case that I'm using it improperly, it would be great to have a similar function to give a hidden element so Blazor does not behave erratically from a changed DOM structure.

Sorry to post this without code to reproduce the issue, but after playing around I'm still struggling to get it to occur again. If this isn't enough information to give insight, I will try again this weekend to reproduce the issue in a smaller project.

RunSynchronously hangs

Running this code makes it hang upon return:

JSRuntime.Current.InvokeAsync( "alert", "Hello!") |> Async.AwaitTask |> Async.RunSynchronously

But this works ok:

JSRuntime.Current.InvokeAsync( "alert", "Hello!") |> Async.AwaitTask |> Async.Start

Add AssemblyInfo

In particular the AssemblyVersion is not set from the package version, and instead is the default 1.0.0.0.

Invalid href value when using router

If we pass / as an endpoint value then it would be trimmed and the resulting href attribute would be invalid.

type ApplicationPage =
    | [<EndPoint "/">]
      Home
a [router.HRef Home] [...]

results in

<a href="">...</a>

when it should be

<a href="/">...</a>

Add DOM element reference

Blazor has the ref="@Property" attribute to capture a reference to the DOM element, with type ElementRef. We should add this capability.

The razor attribute is compiled as:

builder.AddElementReferenceCapture(sequence, (ElementRef __value) => Property = __value)

A simple way to translate this to Bolero would be as an attribute taking a callback, and users would need to have a corresponding Elmish model field and message:

// new API:
// module attr =
//     val ref : (ElementRef -> unit) -> Attr

type Model = { buttonRef: ElementRef }

let initModel = { buttonRef = Unchecked.defaultof<_> }

type Message =
    | SetButtonRef of ElementRef

let update message model =
    match message with
    | SetButtonRef ref -> { model with buttonRef = ref }

let view model dispatch =
    button [
        attr.ref (fun ref -> dispatch (SetButtonRef ref))
        on.click (fun _ -> someJsCallback(model.buttonRef))
    ] [text "Click me!"]

That's not ideal though. I think it would be worth having a helper to include an element ref in a component:

// new API:
// type ElementRefBinder =
//     new : unit -> _
//     member ref : ElementRef
// module attr =
//     val bindRef : ElementRefBinder -> Attr

type View() =
    inherit ElmishComponent<Model, Message>()

    let buttonRef = ElementRefBinder()

    override this.View model dispatch =
        button [
            attr.bindRef buttonRef
            on.click (fun _ -> someJsCallback(buttonRef.ref))
        ] [text "Click me!"]

Document the need for <base> tag for routing

For the router to work properly, notably .Link / .HRef, the page needs to have a correct base, typically set by <base href="/"> in the HTML head. This needs to be documented in the routing page.

[Proposal] EndPoint: Specify full path with placeholders

Proposal: make the EndPoint syntax more complete by specifying the full path with {field} placeholders.

Example:

type Page =
    | [<EndPoint "/article/{id}/{slug}">] Article of id: int * slug: string
    | [<EndPoint "/foo/{b}/bar/{a}">]     MoreComplex of a: (int * string) * b: int

Article(123, "some-string") // -> /article/123/some-string
MoreComplex(456, (123, "some-string")) // -> /foo/123/some-string/bar/456
  • If an EndPoint is just one non-placeholder fragment, it works like currently: fields are added one after another.

  • It is an error for an EndPoint to specify some but not all of the fields.

  • This should support multiple endpoints with a common prefix. For example:

    type CommonConstantPrefix =
        | [<EndPoint "/article/by-id/{id}">]     ById of id: int
        | [<EndPoint "/article/by-slug/{slug}">] BySlug of slug: string
        | [<EndPoint "/article/{slug}">]         Article of slug: string

    In the above:

    • any path starting with /article/by-id is matched with ById
    • any path starting with /article/by-slug is matched with BySlug
    • any other path starting with /article is matched with Article.

    In particular, the path /article/by-id is not matched against Article, even though it would succeed. The parser looks for constant fragments, and if none corresponds, it looks for field fragments; but once it has chosen one of these branches, it does not backtrack.

    Question: is the above a good design? Or should paths that correspond to a constant fragment but fail to match the rest of the pattern be tried against field fragments?

    A common prefix should also be able to include a field. For example:

    type CommonFieldPrefix =
        | [<EndPoint "/user/{id}/followers">] Followers of id: string
        | [<EndPoint "/user/{id}/likes">]     Likes of id: string

    The field name is of course irrelevant and doesn't have to be the same.

    Question: what should happen if two endpoints have a common prefix up to a field with different types? eg:

    type DifferentTypeFieldPrefix =
        | [<EndPoint "/user/{id}/followers">] Followers of id: string
        | [<EndPoint "/user/{id}/likes">]     Likes of id: int
    • Option 1: it's an error. I think this is more consistent and less error prone.
    • Option 2: they're tried in the order in which the cases are declared.

Possible extensions:

  • {*field} to catch the rest of the path, of type string, list<_> or array<_>. It must be unique and at the end of the path.

  • {?field} for optional fields, of type option<_>. They must all be at the end of the path, before {*field} if any.

  • Some form of handling for query parameters. Possible syntax:

    type WithQuery =
        | [<EndPoint "/article/{id}?page={page}&tags={?t}">]
          Article of id: int * page: int * t: option<string>

Add bind functions in plain F#

With templating we have two-way binding with a simple bind="${Hole}" mapped with a current value and a dispatch callback. However the way to do two-way binding in plain F# is more explicit:

input [
    attr.value model.currentValue
    on.input (fun e -> dispatch (SetCurrentValue (e.Value :?> string)))
]

We should provide functions to make it simpler. There are several aspects that they need to take into consideration:

  1. which attribute it must be bound to:
    a. checked for checkbox
    b. value for other inputs
  2. which event it must be bound to:
    a. change for checkbox and select
    b. input or change (customizable) for other inputs
  3. how the value is extracted from UIChangeEventArgs (these are implemented in TemplatingInternals.fs):
    a. :?> bool for checkbox
    b. :?> string for select and string inputs
    c. :?> string and parse for number inputs.

I propose we add a bind module with the following functions:

module bind =
    // 1a, 2a, 3a
    val checked : bool -> (bool -> unit) -> Attr

    // 1b, 2b, 3b
    val input : string -> (string -> unit) -> Attr
    val change : string -> (string -> unit) -> Attr

    // 1b, 2b, 3c
    val inputInt : int -> (int -> unit) -> Attr
    val changeInt : int -> (int -> unit) -> Attr
    val inputFloat : float -> (float -> unit) -> Attr
    val changeFloat : float -> (float -> unit) -> Attr

The motivating example would then be written more clearly:

input [bind.input model.currentValue (dispatch << SetCurrentValue)]

Child/nested components?

How can I extract Model/Message/Html Template for subcomponents into separate folders/files?
The (otherwise excellent) HelloWorld sample has all the code in Main.fs, and all the templates in main.html ...

How to build Bolero without Paket?

I don't use Paket in my solution so I would like to build Bolero without it.
But client-side build breaks

1>------ Build started: Project: Admin, Configuration: Debug Any CPU ------
1>Admin -> C:\Users\Andrii\Dev\SFSync\SalesforceTopicsListener\src\Admin\bin\Debug\netstandard2.0\Admin.dll
1>Cannot find declaration of exported type 'System.Threading.Semaphore' from the assembly 'System.Threading, Version=4.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
1>Cannot find declaration of exported type 'System.AggregateException' from the assembly 'FSharp.Core, Version=4.6.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
1>Cannot find declaration of exported type 'System.Threading.CancellationToken' from the assembly 'FSharp.Core, Version=4.6.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
1>Cannot find declaration of exported type 'System.Threading.CancellationTokenRegistration' from the assembly 'FSharp.Core, Version=4.6.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
1>Cannot find declaration of exported type 'System.Threading.CancellationTokenSource' from the assembly 'FSharp.Core, Version=4.6.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
1>Processing embedded resource linker descriptor: mscorlib.xml
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Threading.ExecutionContext (Nothing).  Duplicate uses (Nothing)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Threading.ExecutionContext System.Threading.ExecutionContext::Capture()
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Threading.ExecutionContext System.Threading.ExecutionContext::Capture(System.Threading.StackCrawlMark&,System.Threading.ExecutionContext/CaptureOptions)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Threading.Interlocked (Nothing).  Duplicate uses (Nothing)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Int32 System.Threading.Interlocked::CompareExchange(System.Int32&,System.Int32,System.Int32)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Int32 System.Threading.Interlocked::CompareExchange(System.Int32&,System.Int32,System.Int32,System.Boolean&)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Object System.Threading.Interlocked::CompareExchange(System.Object&,System.Object,System.Object)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Single System.Threading.Interlocked::CompareExchange(System.Single&,System.Single,System.Single)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Int64 System.Threading.Interlocked::CompareExchange(System.Int64&,System.Int64,System.Int64)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.IntPtr System.Threading.Interlocked::CompareExchange(System.IntPtr&,System.IntPtr,System.IntPtr)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Double System.Threading.Interlocked::CompareExchange(System.Double&,System.Double,System.Double)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of T System.Threading.Interlocked::CompareExchange(T&,T,T)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Int32 System.Threading.Interlocked::Exchange(System.Int32&,System.Int32)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Object System.Threading.Interlocked::Exchange(System.Object&,System.Object)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Single System.Threading.Interlocked::Exchange(System.Single&,System.Single)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Int64 System.Threading.Interlocked::Exchange(System.Int64&,System.Int64)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.IntPtr System.Threading.Interlocked::Exchange(System.IntPtr&,System.IntPtr)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Double System.Threading.Interlocked::Exchange(System.Double&,System.Double)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of T System.Threading.Interlocked::Exchange(T&,T)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Threading.Monitor (Nothing).  Duplicate uses (Nothing)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Void System.Threading.Monitor::Enter(System.Object)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Void System.Threading.Monitor::Enter(System.Object,System.Boolean&)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Void System.Threading.Monitor::Exit(System.Object)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Threading.ManualResetEvent (Nothing).  Duplicate uses (Nothing)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Void System.Threading.ManualResetEvent::.ctor(System.Boolean)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Threading.SynchronizationLockException (Nothing).  Duplicate uses (Nothing)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Void System.Threading.SynchronizationLockException::.ctor(System.String)
1>Duplicate preserve in resource mscorlib.xml in mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of System.Threading.WasmRuntime (All).  Duplicate uses (All)
1>Fatal error in IL Linker
1>Mono.Linker.MarkException: Error processing method: 'System.Void Bolero.Templating.Client.SignalRClient::.ctor(Bolero.Templating.HotReloadSettings)' in assembly: 'Bolero.Templating.dll' ---> Mono.Cecil.ResolutionException: Failed to resolve System.Void Blazor.Extensions.HubConnection::OnClose(System.Func`2<System.Exception,System.Threading.Tasks.Task>)
1>   at Mono.Linker.Steps.MarkStep.HandleUnresolvedMethod(MethodReference reference)
1>   at Mono.Linker.Steps.MarkStep.MarkMethod(MethodReference reference)
1>   at Mono.Linker.Steps.MarkStep.MarkInstruction(Instruction instruction)
1>   at Mono.Linker.Steps.MarkStep.MarkMethodBody(MethodBody body)
1>   at Mono.Linker.Steps.MarkStep.ProcessMethod(MethodDefinition method)
1>   at Mono.Linker.Steps.MarkStep.ProcessQueue()
1>   --- End of inner exception stack trace ---
1>   at Mono.Linker.Steps.MarkStep.ProcessQueue()
1>   at Mono.Linker.Steps.MarkStep.ProcessPrimaryQueue()
1>   at Mono.Linker.Steps.MarkStep.Process()
1>   at Mono.Linker.Steps.MarkStep.Process(LinkContext context)
1>   at Mono.Linker.Pipeline.ProcessStep(LinkContext context, IStep step)
1>   at Mono.Linker.Pipeline.Process(LinkContext context)
1>   at Mono.Linker.Driver.Run(ILogger customLogger)
1>   at Mono.Linker.Driver.Execute(String[] args, ILogger customLogger)
1>C:\Users\Andrii\.nuget\packages\microsoft.aspnetcore.blazor.build\0.7.0\targets\Blazor.MonoRuntime.targets(439,5): error MSB3073: The command "dotnet "C:\Users\Andrii\.nuget\packages\microsoft.aspnetcore.blazor.build\0.7.0\targets\../tools/illink/illink.dll" -l none --verbose --strip-security true --exclude-feature com --exclude-feature sre -v false -c link -u link -b true -d "C:\Users\Andrii\.nuget\packages\microsoft.aspnetcore.blazor.build\0.7.0\targets\../tools/mono/bcl/" -d "C:\Users\Andrii\.nuget\packages\microsoft.aspnetcore.blazor.build\0.7.0\targets\../tools/mono/bcl/Facades/" -o "C:\Users\Andrii\Dev\SFSync\SalesforceTopicsListener\src\Admin\obj\Debug\netstandard2.0\blazor\linker/" -x "C:\Users\Andrii\.nuget\packages\microsoft.aspnetcore.blazor.build\0.7.0\targets\BuiltInBclLinkerDescriptor.xml" -x "C:\Users\Andrii\Dev\SFSync\SalesforceTopicsListener\src\Admin\obj\Debug\netstandard2.0\blazor\linker.descriptor.xml" -a "C:\Users\Andrii\.nuget\packages\blazor.extensions.signalr\0.1.0\lib\netstandard2.0\Blazor.Extensions.SignalR.JS.dll" -a "C:\Users\Andrii\.nuget\packages\blazor.extensions.signalr\0.1.0\lib\netstandard2.0\Blazor.Extensions.SignalR.dll" -a "C:\Users\Andrii\.nuget\packages\bolero\0.3.130\lib\netstandard2.0\Bolero.Server.dll" -a "C:\Users\Andrii\.nuget\packages\bolero\0.3.130\lib\netstandard2.0\Bolero.dll" -a "C:\Users\Andrii\.nuget\packages\bolero.hotreload\0.3.130\lib\netstandard2.0\Bolero.Templating.dll" -a "C:\Users\Andrii\.nuget\packages\elmish\2.0.0\lib\netstandard2.0\Elmish.dll" -a "C:\Users\Andrii\.nuget\packages\fsharp.core\4.6.2\lib\netstandard1.6\FSharp.Core.dll" -a "C:\Users\Andrii\.nuget\packages\htmlagilitypack\1.8.0\lib\netstandard2.0\HtmlAgilityPack.dll" -a "C:\Users\Andrii\.nuget\packages\microsoft.aspnetcore.blazor\0.7.0\lib\netstandard2.0\Microsoft.AspNetCore.Blazor.dll" -a "C:\Users\Andrii\.nuget\packages\microsoft.aspnetcore.blazor.browser\0.7.0\lib\netstandard2.0\Microsoft.AspNetCore.Blazor.Browser.dll" -a "C:\Users\Andrii\.nuget\packages\microsoft.aspnetcore.blazor.build\0.7.0\lib\netstandard1.0\Microsoft.AspNetCore.Blazor.TagHelperWorkaround.dll" -a "C:\Users\Andrii\.nuget\packages\microsoft.aspnetcore.http.abstractions\2.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Abstractions.dll" -a "C:\Users\Andrii\.nuget\packages\microsoft.aspnetcore.http.features\2.1.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Features.dll" -a "C:\Users\Andrii\.nuget\packages\microsoft.extensions.dependencyinjection\2.1.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.dll" -a "C:\Users\Andrii\.nuget\packages\microsoft.extensions.dependencyinjection.abstractions\2.1.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll" -a "C:\Users\Andrii\.nuget\packages\microsoft.extensions.primitives\2.1.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll" -a "C:\Users\Andrii\.nuget\packages\microsoft.jsinterop\0.7.0\lib\netstandard2.0\Microsoft.JSInterop.dll" -a "C:\Users\Andrii\.nuget\packages\mono.webassembly.interop\0.7.0\lib\netstandard2.0\Mono.WebAssembly.Interop.dll" -a "C:\Users\Andrii\.nuget\packages\system.buffers\4.4.0\lib\netstandard2.0\System.Buffers.dll" -a "C:\Users\Andrii\.nuget\packages\system.collections.concurrent\4.3.0\lib\netstandard1.3\System.Collections.Concurrent.dll" -a "C:\Users\Andrii\.nuget\packages\system.diagnostics.diagnosticsource\4.3.0\lib\netstandard1.3\System.Diagnostics.DiagnosticSource.dll" -a "C:\Users\Andrii\.nuget\packages\system.io.filesystem.primitives\4.3.0\lib\netstandard1.3\System.IO.FileSystem.Primitives.dll" -a "C:\Users\Andrii\.nuget\packages\system.linq\4.3.0\lib\netstandard1.6\System.Linq.dll" -a "C:\Users\Andrii\.nuget\packages\system.memory\4.5.0\lib\netstandard2.0\System.Memory.dll" -a "C:\Users\Andrii\.nuget\packages\system.numerics.vectors\4.4.0\lib\netstandard2.0\System.Numerics.Vectors.dll" -a "C:\Users\Andrii\.nuget\packages\system.runtime.compilerservices.unsafe\4.5.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll" -a "C:\Users\Andrii\.nuget\packages\system.runtime.numerics\4.3.0\lib\netstandard1.3\System.Runtime.Numerics.dll" -a "C:\Users\Andrii\.nuget\packages\system.security.cryptography.openssl\4.3.0\lib\netstandard1.6\System.Security.Cryptography.OpenSsl.dll" -a "C:\Users\Andrii\.nuget\packages\system.security.cryptography.primitives\4.3.0\lib\netstandard1.3\System.Security.Cryptography.Primitives.dll" -a "C:\Users\Andrii\.nuget\packages\system.text.encodings.web\4.5.0\lib\netstandard2.0\System.Text.Encodings.Web.dll" -a "C:\Users\Andrii\.nuget\packages\system.text.regularexpressions\4.3.0\lib\netstandard1.6\System.Text.RegularExpressions.dll" -a "C:\Users\Andrii\.nuget\packages\system.threading\4.3.0\lib\netstandard1.3\System.Threading.dll" -a "C:\Users\Andrii\.nuget\packages\system.threading.tasks.extensions\4.3.0\lib\netstandard1.0\System.Threading.Tasks.Extensions.dll" -a "C:\Users\Andrii\.nuget\packages\system.xml.readerwriter\4.3.0\lib\netstandard1.3\System.Xml.ReaderWriter.dll" -a "C:\Users\Andrii\.nuget\packages\system.xml.xmldocument\4.3.0\lib\netstandard1.3\System.Xml.XmlDocument.dll" -a "C:\Users\Andrii\.nuget\packages\system.xml.xpath\4.3.0\lib\netstandard1.3\System.Xml.XPath.dll" -a "C:\Users\Andrii\.nuget\packages\system.xml.xpath.xmldocument\4.3.0\lib\netstandard1.3\System.Xml.XPath.XmlDocument.dll" -a "C:\Users\Andrii\.nuget\packages\fsharp.core\4.6.2\lib\netstandard1.6\cs\FSharp.Core.resources.dll" -a "C:\Users\Andrii\.nuget\packages\fsharp.core\4.6.2\lib\netstandard1.6\de\FSharp.Core.resources.dll" -a "C:\Users\Andrii\.nuget\packages\fsharp.core\4.6.2\lib\netstandard1.6\en\FSharp.Core.resources.dll" -a "C:\Users\Andrii\.nuget\packages\fsharp.core\4.6.2\lib\netstandard1.6\es\FSharp.Core.resources.dll" -a "C:\Users\Andrii\.nuget\packages\fsharp.core\4.6.2\lib\netstandard1.6\fr\FSharp.Core.resources.dll" -a "C:\Users\Andrii\.nuget\packages\fsharp.core\4.6.2\lib\netstandard1.6\it\FSharp.Core.resources.dll" -a "C:\Users\Andrii\.nuget\packages\fsharp.core\4.6.2\lib\netstandard1.6\ja\FSharp.Core.resources.dll" -a "C:\Users\Andrii\.nuget\packages\fsharp.core\4.6.2\lib\netstandard1.6\ko\FSharp.Core.resources.dll" -a "C:\Users\Andrii\.nuget\packages\fsharp.core\4.6.2\lib\netstandard1.6\pl\FSharp.Core.resources.dll" -a "C:\Users\Andrii\.nuget\packages\fsharp.core\4.6.2\lib\netstandard1.6\pt-BR\FSharp.Core.resources.dll" -a "C:\Users\Andrii\.nuget\packages\fsharp.core\4.6.2\lib\netstandard1.6\ru\FSharp.Core.resources.dll" -a "C:\Users\Andrii\.nuget\packages\fsharp.core\4.6.2\lib\netstandard1.6\tr\FSharp.Core.resources.dll" -a "C:\Users\Andrii\.nuget\packages\fsharp.core\4.6.2\lib\netstandard1.6\zh-Hans\FSharp.Core.resources.dll" -a "C:\Users\Andrii\.nuget\packages\fsharp.core\4.6.2\lib\netstandard1.6\zh-Hant\FSharp.Core.resources.dll" -a "C:\Users\Andrii\Dev\SFSync\SalesforceTopicsListener\src\Admin\obj\Debug\netstandard2.0\Admin.dll"" exited with code 1.
1>Done building project "Admin.fsproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <RunCommand>dotnet</RunCommand>
    <RunArguments>blazor serve</RunArguments>
  </PropertyGroup>

  <ItemGroup>
    <Compile Include="Main.fs" />
    <Compile Include="Startup.fs" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Bolero.Build" Version="0.3.130" />
    <PackageReference Include="Bolero.HotReload" Version="0.3.130" />
    <PackageReference Include="Microsoft.AspNetCore.Blazor.Build" Version="0.7.0" />
    <!--<PackageReference Include="Microsoft.AspNetCore.Blazor.Cli" Version="0.7.0" />-->
  </ItemGroup>

</Project>

How do I add css elements?

I know how to use styles with attr.style but I don’t know how to define keyframes such as:

@keyframes fade { 0% { background-color: white } 100% { background-color: red } }

RemoteResponse is redundant

The type RemoteResponse<'T> is isomorphic to option<'T>, and causes unnecessary verbosity in code such as:

Cmd.ofRemote remote.func arg (fun r -> OnSuccess (r.TryGetResponse())) OnError

It has the advantage of being explicit though; if we had a function ofRemote that passes an option<'T>, it wouldn't be clear what it means to receive None from it. So I propose the following:

  • Deprecate RemoteResponse<'T> and the associated Cmd.ofRemote and Cmd.performRemote.
  • Add the following functions, with the same semantics as Cmd.ofRemote and Cmd.performRemote:
    module Cmd =
        val ofAuthorized
             : remoteFunction: ('req -> Async<'resp>)
            -> arg: 'req
            -> onResult: (option<'resp> -> 'msg)
            -> onError: (exn -> 'msg)
            -> Cmd<'msg>
    
        val performAuthorized
             : remoteFunction: ('req -> Async<'resp>)
            -> arg: 'req
            -> onResult: (option<'resp> -> 'msg)
            -> Cmd<'msg>

The above example then becomes:

Cmd.ofAuthorized remote.func arg OnSuccess OnError

At the same time, this would clear out the ambiguity of the name Cmd.ofRemote. As it stands, it may cause beginners to believe that they have to use it to call a remote function, whereas in reality you can use Cmd.ofAsync just as well, and you should if you're not dealing with authorization.

Update nuget package

The package on nuget.org has not been updated for the changes in #13, which added functionality for using element refs.

Are there plans to publish these changes?

Remoting Authentication

Is it possible to incorporate authentication into remote requests? Something along the lines of attaching a header value to include a JWT token to be included in the HTTP request?

Templating: error when using a hole in a node and in its children

The following:

type T = Template<"""<span class="${Hole}">${Hole}</span>""">

fails to compile with the message:

error FS3033: The type provider 'Bolero.Templating.Template' reported an error: unknown parameter/field

The message "unknown parameter/field" seems to come from ProvidedTypes.fs.

Update to .NET Core 3.0-preview6

with .net core 3.0 preview 6 , I am getting below error:

Application startup exception: System.TypeLoadException: Could not load type 'Microsoft.AspNetCore.Authorization.IAuthorizeData' from assembly 'Microsoft.AspNetCore.Http.Abstractions, Version=3.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'.
   at Bolero.Remoting.Server.Remote.authorize[req,resp](FSharpFunc`2 f)
   at HelloWorld.Server.BookService.get_Handler() in D:\playground\bolero2\HelloWorld\src\HelloWorld.Server\Startup.fs:line 26
   at Bolero.Remoting.Server.RemoteHandler`1.Bolero-Remoting-Server-IRemoteHandler-get_Handler()
   at <StartupCode$Bolero-Server>[email protected](IServiceProvider services)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSit

Templating: bind: allow choosing between oninput and onchange

Currently bind always uses onchange to listen for changes, which means that changes are only propagated when a change is committed. For example on a text input, changes are only propagated when the user removes focus from the input or presses Enter. In contrast, oninput would trigger the event on every keystroke instead. This was a source of subtle bugs in TodoMVC because the changes are propagated after blur instead of before.

I think we should have the default behavior be oninput, with an option to use onchange instead. Proposed syntax for this option: bind-onchange="${Hole}".

This depends on #3 because Blazor 0.7 implements UIChangeEventArgs for oninput, which is needed to retrieve the value.

JS/React interop?

I have previously experimented a bit with Fable and React and really like the experience, but compiling to JS is a significant drawback for a .NET dev like me since 1) it's a different runtime environment than I'm used to and I have to constantly think about that while coding, and 2) I can't use any nugets except those few that have been specifically designed to work with Fable (i.e., includes sources in the .nupkg).

I came across Bolero in a recent F# Weekly, and was thrilled, to say the least. I know next to nothing about Blazor or WebAssembly, but AFAIK this project makes it possible to run .NET code directly in the browser, using nugets and a runtime environment that is familiar to .NET devs (please correct me if I'm wrong).

However, having delved into Fable/React/Material-UI a lot recently, I have two questions:

  1. JS interop. The Writing HTML part of the docs shows plain old HTML elements. In order to create the rich/complex UIs often needed today, one might need packages/frameworks like Bootstrap, Bulma, React, or Material-UI (which requires React). The JS ecosystem is incredibly rich. Is there a story here for Bolero? Is it possible? Simple? Are there similar/better alternatives?

  2. Elmish performance. Fable/React/Elmish uses React for rendering, which is lightning quick. Can I expect the Bolero/Elmish combo to scale similarly (using ElmishComponent and ShouldRender similarly to lazy in Elmish.React)?

Problems with GetStarted

I just discovered Bolero and I am eager to try it, but I am having problems with GetStarted example

Following directions from the home page I performed following steps

dotnet new -i Bolero.Templates
dotnet new bolero-app -o MyApp
dotnet run -p src/MyApp.Server

and received following error

C:\Users\Dejan\.nuget\packages\microsoft.aspnetcore.blazor.build\0.7.0\targets\Blazor.MonoRuntime.targets(439,5): error MSB3073: The command "dotnet "C:\Users\Dejan\.nuget\packages\microsoft.aspnetcore.blazor.build\0.7.0\targets\../tools/illink/illink.dll" -l none --verbose --strip-security true --exclude-feature com --exclude-feature sre -v false -c link -u link -b true -d "C:\Users\Dejan\.nuget\packages\microsoft.aspnetcore.blazor.build\0.7.0\targets\../tools/mono/bcl/" -d "C:\Users\Dejan\.nuget\packages\microsoft.aspnetcore.blazor.build\0.7.0\targets\../tools/mono/bcl/Facades/" -o "C:\temp\MyApp\src\MyApp.Client\obj\Debug\netstandard2.0\blazor\linker/" -x "C:\Users\Dejan\.nuget\packages\microsoft.aspnetcore.blazor.build\0.7.0\targets\BuiltInBclLinkerDescriptor.xml" -x "C:\temp\MyApp\src\MyApp.Client\obj\Debug\netstandard2.0\blazor\linker.descriptor.xml" -a "C:\Users\Dejan\.nuget\packages\blazor.extensions.signalr\0.1.8\lib\netstandard2.0\Blazor.Extensions.SignalR.JS.dll" -a "C:\Users\Dejan\.nuget\packages\blazor.extensions.signalr\0.1.8\lib\netstandard2.0\Blazor.Extensions.SignalR.dll" -a "C:\Users\Dejan\.nuget\packages\bolero\0.4.144\lib\netstandard2.0\Bolero.dll" -a "C:\Users\Dejan\.nuget\packages\bolero.hotreload\0.4.144\lib\netstandard2.0\Bolero.Templating.dll" -a "C:\Users\Dejan\.nuget\packages\elmish\2.0.3\lib\netstandard2.0\Elmish.dll" -a "C:\Users\Dejan\.nuget\packages\fsharp.core\4.5.4\lib\netstandard1.6\FSharp.Core.dll" -a "C:\Users\Dejan\.nuget\packages\htmlagilitypack\1.11.1\lib\netstandard2.0\HtmlAgilityPack.dll" -a "C:\Users\Dejan\.nuget\packages\microsoft.aspnetcore.blazor\0.7.0\lib\netstandard2.0\Microsoft.AspNetCore.Blazor.dll" -a "C:\Users\Dejan\.nuget\packages\microsoft.aspnetcore.blazor.browser\0.7.0\lib\netstandard2.0\Microsoft.AspNetCore.Blazor.Browser.dll" -a "C:\Users\Dejan\.nuget\packages\microsoft.aspnetcore.blazor.build\0.7.0\lib\netstandard1.0\Microsoft.AspNetCore.Blazor.TagHelperWorkaround.dll" -a "C:\Users\Dejan\.nuget\packages\microsoft.aspnetcore.http.abstractions\2.1.1\lib\netstandard2.0\Microsoft.AspNetCore.Http.Abstractions.dll" -a "C:\Users\Dejan\.nuget\packages\microsoft.aspnetcore.http.features\2.1.1\lib\netstandard2.0\Microsoft.AspNetCore.Http.Features.dll" -a "C:\Users\Dejan\.nuget\packages\microsoft.extensions.dependencyinjection\2.1.1\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.dll" -a "C:\Users\Dejan\.nuget\packages\microsoft.extensions.dependencyinjection.abstractions\2.1.1\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll" -a "C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.extensions.primitives\2.1.1\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll" -a "C:\Users\Dejan\.nuget\packages\microsoft.jsinterop\0.7.0\lib\netstandard2.0\Microsoft.JSInterop.dll" -a
"C:\Users\Dejan\.nuget\packages\mono.webassembly.interop\0.7.0\lib\netstandard2.0\Mono.WebAssembly.Interop.dll" -a "C:\Users\Dejan\.nuget\packages\system.buffers\4.4.0\lib\netstandard2.0\System.Buffers.dll" -a "C:\Users\Dejan\.nuget\packages\system.collections.concurrent\4.3.0\lib\netstandard1.3\System.Collections.Concurrent.dll" -a "C:\Users\Dejan\.nuget\packages\system.diagnostics.diagnosticsource\4.5.1\lib\netstandard1.3\System.Diagnostics.DiagnosticSource.dll" -a "C:\Users\Dejan\.nuget\packages\system.io.filesystem.primitives\4.3.0\lib\netstandard1.3\System.IO.FileSystem.Primitives.dll" -a "C:\Users\Dejan\.nuget\packages\system.linq\4.3.0\lib\netstandard1.6\System.Linq.dll" -a "C:\Users\Dejan\.nuget\packages\system.memory\4.5.1\lib\netstandard2.0\System.Memory.dll" -a "C:\Users\Dejan\.nuget\packages\system.numerics.vectors\4.4.0\lib\netstandard2.0\System.Numerics.Vectors.dll" -a "C:\Users\Dejan\.nuget\packages\system.runtime.compilerservices.unsafe\4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll"
-a "C:\Users\Dejan\.nuget\packages\system.runtime.numerics\4.3.0\lib\netstandard1.3\System.Runtime.Numerics.dll" -a "C:\Users\Dejan\.nuget\packages\system.security.cryptography.cng\4.5.0\lib\netstandard2.0\System.Security.Cryptography.Cng.dll" -a "C:\Users\Dejan\.nuget\packages\system.security.cryptography.openssl\4.5.1\lib\netstandard2.0\System.Security.Cryptography.OpenSsl.dll" -a "C:\Users\Dejan\.nuget\packages\system.security.cryptography.primitives\4.3.0\lib\netstandard1.3\System.Security.Cryptography.Primitives.dll" -a "C:\Users\Dejan\.nuget\packages\system.text.encodings.web\4.5.0\lib\netstandard2.0\System.Text.Encodings.Web.dll" -a "C:\Users\Dejan\.nuget\packages\system.text.regularexpressions\4.3.0\lib\netstandard1.6\System.Text.RegularExpressions.dll" -a "C:\Users\Dejan\.nuget\packages\system.threading\4.3.0\lib\netstandard1.3\System.Threading.dll" -a "C:\Users\Dejan\.nuget\packages\system.threading.tasks.extensions\4.5.2\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll" -a "C:\Users\Dejan\.nuget\packages\system.xml.readerwriter\4.3.1\lib\netstandard1.3\System.Xml.ReaderWriter.dll" -a "C:\Users\Dejan\.nuget\packages\system.xml.xmldocument\4.3.0\lib\netstandard1.3\System.Xml.XmlDocument.dll" -a "C:\Users\Dejan\.nuget\packages\system.xml.xpath\4.3.0\lib\netstandard1.3\System.Xml.XPath.dll" -a "C:\Users\Dejan\.nuget\packages\system.xml.xpath.xmldocument\4.3.0\lib\netstandard1.3\System.Xml.XPath.XmlDocument.dll" -a "C:\Users\Dejan\.nuget\packages\fsharp.core\4.5.4\lib\netstandard1.6\cs\FSharp.Core.resources.dll" -a "C:\Users\Dejan\.nuget\packages\fsharp.core\4.5.4\lib\netstandard1.6\de\FSharp.Core.resources.dll" -a "C:\Users\Dejan\.nuget\packages\fsharp.core\4.5.4\lib\netstandard1.6\en\FSharp.Core.resources.dll" -a "C:\Users\Dejan\.nuget\packages\fsharp.core\4.5.4\lib\netstandard1.6\es\FSharp.Core.resources.dll" -a "C:\Users\Dejan\.nuget\packages\fsharp.core\4.5.4\lib\netstandard1.6\fr\FSharp.Core.resources.dll" -a "C:\Users\Dejan\.nuget\packages\fsharp.core\4.5.4\lib\netstandard1.6\it\FSharp.Core.resources.dll" -a "C:\Users\Dejan\.nuget\packages\fsharp.core\4.5.4\lib\netstandard1.6\ja\FSharp.Core.resources.dll" -a "C:\Users\Dejan\.nuget\packages\fsharp.core\4.5.4\lib\netstandard1.6\ko\FSharp.Core.resources.dll" -a "C:\Users\Dejan\.nuget\packages\fsharp.core\4.5.4\lib\netstandard1.6\pl\FSharp.Core.resources.dll"
-a "C:\Users\Dejan\.nuget\packages\fsharp.core\4.5.4\lib\netstandard1.6\pt-BR\FSharp.Core.resources.dll" -a "C:\Users\Dejan\.nuget\packages\fsharp.core\4.5.4\lib\netstandard1.6\ru\FSharp.Core.resources.dll" -a "C:\Users\Dejan\.nuget\packages\fsharp.core\4.5.4\lib\netstandard1.6\tr\FSharp.Core.resources.dll" -a "C:\Users\Dejan\.nuget\packages\fsharp.core\4.5.4\lib\netstandard1.6\zh-Hans\FSharp.Core.resources.dll" -a "C:\Users\Dejan\.nuget\packages\fsharp.core\4.5.4\lib\netstandard1.6\zh-Hant\FSharp.Core.resources.dll" -a "C:\Users\Dejan\.nuget\packages\system.globalization.extensions\4.3.0\runtimes\unix\lib\netstandard1.3\System.Globalization.Extensions.dll" -a "C:\Users\Dejan\.nuget\packages\system.globalization.extensions\4.3.0\runtimes\win\lib\netstandard1.3\System.Globalization.Extensions.dll" -a "C:\Users\Dejan\.nuget\packages\system.net.http\4.3.4\runtimes\unix\lib\netstandard1.6\System.Net.Http.dll" -a "C:\Users\Dejan\.nuget\packages\system.net.http\4.3.4\runtimes\win\lib\netstandard1.3\System.Net.Http.dll" -a "C:\Users\Dejan\.nuget\packages\system.security.cryptography.algorithms\4.3.1\runtimes\osx\lib\netstandard1.6\System.Security.Cryptography.Algorithms.dll" -a "C:\Users\Dejan\.nuget\packages\system.security.cryptography.algorithms\4.3.1\runtimes\unix\lib\netstandard1.6\System.Security.Cryptography.Algorithms.dll" -a "C:\Users\Dejan\.nuget\packages\system.security.cryptography.algorithms\4.3.1\runtimes\win\lib\netstandard1.6\System.Security.Cryptography.Algorithms.dll" -a "C:\Users\Dejan\.nuget\packages\system.security.cryptography.cng\4.5.0\runtimes\win\lib\netstandard1.6\System.Security.Cryptography.Cng.dll" -a "C:\Users\Dejan\.nuget\packages\system.security.cryptography.csp\4.3.0\runtimes\unix\lib\netstandard1.3\System.Security.Cryptography.Csp.dll" -a "C:\Users\Dejan\.nuget\packages\system.security.cryptography.csp\4.3.0\runtimes\win\lib\netstandard1.3\System.Security.Cryptography.Csp.dll" -a "C:\Users\Dejan\.nuget\packages\system.security.cryptography.encoding\4.3.0\runtimes\unix\lib\netstandard1.3\System.Security.Cryptography.Encoding.dll" -a "C:\Users\Dejan\.nuget\packages\system.security.cryptography.encoding\4.3.0\runtimes\win\lib\netstandard1.3\System.Security.Cryptography.Encoding.dll" -a "C:\Users\Dejan\.nuget\packages\system.security.cryptography.openssl\4.5.1\runtimes\unix\lib\netstandard1.6\System.Security.Cryptography.OpenSsl.dll" -a "C:\Users\Dejan\.nuget\packages\system.security.cryptography.x509certificates\4.3.2\runtimes\unix\lib\netstandard1.6\System.Security.Cryptography.X509Certificates.dll" -a "C:\Users\Dejan\.nuget\packages\system.security.cryptography.x509certificates\4.3.2\runtimes\win\lib\netstandard1.6\System.Security.Cryptography.X509Certificates.dll" -a "C:\temp\MyApp\src\MyApp.Client\obj\Debug\netstandard2.0\MyApp.Client.dll"" exited with code 1. [C:\temp\MyApp\src\MyApp.Client\MyApp.Client.fsproj]

The build failed. Please fix the build errors and run again.

My system info

PS C:\temp\MyApp> dotnet --info
.NET Core SDK (reflecting any global.json):
 Version:   3.0.100-preview3-010431
 Commit:    d72abce213

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.17763
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\3.0.100-preview3-010431\

Host (useful for support):
  Version: 3.0.0-preview3-27503-5
  Commit:  3844df9537

.NET Core SDKs installed:
  1.1.10 [C:\Program Files\dotnet\sdk]
  1.1.11 [C:\Program Files\dotnet\sdk]
  1.1.12 [C:\Program Files\dotnet\sdk]
  1.1.13 [C:\Program Files\dotnet\sdk]
  2.1.202 [C:\Program Files\dotnet\sdk]
  2.1.401 [C:\Program Files\dotnet\sdk]
  2.1.402 [C:\Program Files\dotnet\sdk]
  2.1.403 [C:\Program Files\dotnet\sdk]
  2.1.500 [C:\Program Files\dotnet\sdk]
  2.1.502 [C:\Program Files\dotnet\sdk]
  2.1.503 [C:\Program Files\dotnet\sdk]
  2.1.504 [C:\Program Files\dotnet\sdk]
  2.1.505 [C:\Program Files\dotnet\sdk]
  2.1.600 [C:\Program Files\dotnet\sdk]
  2.1.601 [C:\Program Files\dotnet\sdk]
  2.1.602 [C:\Program Files\dotnet\sdk]
  2.1.604 [C:\Program Files\dotnet\sdk]
  2.2.101 [C:\Program Files\dotnet\sdk]
  2.2.200 [C:\Program Files\dotnet\sdk]
  2.2.201 [C:\Program Files\dotnet\sdk]
  2.2.202 [C:\Program Files\dotnet\sdk]
  2.2.204 [C:\Program Files\dotnet\sdk]
  3.0.100-preview3-010431 [C:\Program Files\dotnet\sdk]

.NET Core runtimes installed:
  Microsoft.AspNetCore.All 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.0.0-preview3-19153-02 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 1.0.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 1.0.13 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 1.0.14 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 1.0.15 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 1.1.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 1.1.10 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 1.1.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 1.1.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.3-servicing-26724-03 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.8 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.0.0-preview3-27503-5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.0.0-preview3-27504-2 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Routing behaves strangely with anchor hashes

Currently routing behaves strangely with anchor tags when the <base href="/" /> is present in the index.html <head>

If you go to a URL with a hash, ex: /callback#43 you will automatically be sent to the root (or possibly first defined) route. However, this does not happen when the base tag is missing from index.html. Instead it will redirect you to /callback without the hash. Note, this only happens if you open a new browser window/tab and go to the URL manually.

Sample code:

module RouteTest.Client.Main

open Elmish
open Bolero
open Bolero.Router
open Bolero.Remoting
open Bolero.Html

type Page =
    | [<EndPoint "/">]
      Home
    | [<EndPoint "/callback">]
      Callback

type Model = { Page: Page; Counter: int }
type Message =
    | SetPage of Page

let router = Router.infer SetPage (fun m -> m.Page)
let loadModel _ = { Page = Home; Counter = 0 }, Cmd.none

let update message model =
    match message with
    | SetPage p ->
        { model with Page = p }, Cmd.none

let view model dispatch =
    div [] [
        cond model.Page <| function
        | Page.Home ->
            div [] [
                p [] []
                a [ attr.href "/callback#43" ]
                    [ text "Callback#43" ]
                p [] []
                a [ attr.href "/callback" ]
                    [ text "Callback" ]
            ]
        | Page.Callback ->
            div [] [
                span [] 
                    [ text "Inside /callback" ]

                p [] []
                a [ attr.href "/callback#43" ] 
                    [ text "43" ]

                div [] [
                    forEach [1..100] (fun i ->
                        p [] [
                            a [ attr.id <| i.ToString() ] []
                            span [] [ textf "%d" i ]
                        ]
                    )
                ]
            ]
    ]

type App() =
    inherit ProgramComponent<Model, Message>()
    override this.Program =
        Program.mkProgram loadModel update view
        |> Program.withRouter router

You also might notice that clicking the /callback#43 link at the root page doesn't seem to work, while the /callback link does. In the callback page the /callback#43 link does not work, yet pasting that URL into the current tab does, but I don't think that's necessarily related

“System.MissingMethodException: Cannot create an abstract class” when passing function as an argument in Remote service.

Hello everyone,

Thank you for this library, I’m having really good time using it :)

I was creating a simple data grid when I got on this error. It occurs when I’m trying to pass a predicate to the server-side as an argument.

type RuleService =
    {
        /// Gets rules by predicate
        getRules: (Rule -> bool) -> Async<Rule[]>
    }


type RuleService(env: IHostingEnvironment) =
    inherit RemoteHandler<Client.Main.RuleService>()

    override this.Handler =
        {
            getRules = Remote.withContext <| fun http _ -> async {
                return rules
            }
        }
fail: Microsoft.AspNetCore.Server.Kestrel[13]
      Connection id "0HLM7NQBFM0I3", Request id "0HLM7NQBFM0I3:00000003": An unhandled exception was thrown by the application.
System.MissingMethodException: Cannot create an abstract class.
   at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean wrapExceptions, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor)
   at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean wrapExceptions, Boolean skipCheckThis, Boolean fillCache)
   at System.Activator.CreateInstance(Type type, Boolean nonPublic, Boolean wrapExceptions)
   at [email protected](Value x)
   at <StartupCode$Bolero-Server>.$Remoting.run@116(FSharpFunc`2 decoder, FSharpFunc`2 encoder, Object meth, MethodInfo callMeth, MethodInfo output, HttpContext ctx, Unit unitVar0)
   at <StartupCode$Bolero-Server>[email protected](IAuthorizationService auth, HttpContext ctx)
   at Bolero.Remoting.Server.RemotingService.TryHandle(HttpContext ctx, IAuthorizationService auth)
   at Microsoft.FSharp.Collections.ArrayModule.TryPick[T,TResult](FSharpFunc`2 chooser, T[] array)
   at <StartupCode$Bolero-Server>[email protected](HttpContext ctx, Func`1 next)
   at Microsoft.AspNetCore.Builder.UseExtensions.<>c__DisplayClass0_1.<Use>b__1(HttpContext context)
   at Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Hosting.Internal.RequestServicesContainerMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Hosting.Internal.HostingApplication.ProcessRequestAsync(Context context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

The error is thrown at runtime.

I haven’t checked exactly what’s happening under the hood, but it clearly has something to do with predicate serialization.

I’m guessing Bolero (or Blazor) is using Newtonsoft as default JSON serializer which doesn’t support function serialization very well.

I’ve done very little research and found that FsPickler can serialize functions.

Passing functions between client and server in frameworks like Bolero would be very beneficial, IMO.

Since I’m just a F# beginner and have very little practice in this land, I’d like to hear from you if I’m doing something wrong or there is a missing part in Bolero/Blazor which hasn’t been filled yet :)

Is it possible to split state?

The sample uses one model object, one message type and one update function. Even with the sample, simple as it is, it's easy to see how quickly this approach gets out of hand.

I took the sample and split it into 3 separate pages, and tried to split the model and messages into different types as well. I can do something like this at the top level:

type Message = CounterMessage of CounterMessage | DataMessage of DataMessage
type Model = { counterModel: CounterModel; dataModel: DataModel }

but doing this every time results in lots of boilerplate and much room for error, so I'm working on a solution to automatically manage the composition of many such "stateful" components. I expect the end result to look like redux's "reducer combination", but it'll split messages and models up as well. I expect to have the code ready in a short while, and I'll post it here when it is.

In the meantime, is something like this already available and I just missed it? Or is it even the right thing to do?

Implement element key

This is a Blazor preview6 feature and therefore depends on #59.

Blazor has a new @key attribute (see announcement) which allows identifying an element in a collection for better diffing, similar to key in React. We should implement an equivalent in Bolero.

Exception when building from Visual Studio

With added logging in Bolero.Build/Task, this is the stack trace:

3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error : FAILING HERE on C:\my\bolero\tests\Client\obj\Debug\netstandard2.0\blazor\linker\Bolero.dll: Mono.Cecil.AssemblyResolutionException: Failed to resolve assembly: 'mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e'
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.BaseAssemblyResolver.Resolve(AssemblyNameReference name, ReaderParameters parameters)
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.DefaultAssemblyResolver.Resolve(AssemblyNameReference name)
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.MetadataResolver.Resolve(TypeReference type)
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.TypeReference.Resolve()
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.Mixin.CheckedResolve(TypeReference self)
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.MetadataBuilder.GetConstantType(TypeReference constant_type, Object constant)
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.MetadataBuilder.AddConstant(IConstantProvider owner, TypeReference type)
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.MetadataBuilder.AddField(FieldDefinition field)
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.MetadataBuilder.AddFields(TypeDefinition type)
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.MetadataBuilder.AddType(TypeDefinition type)
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.MetadataBuilder.AddTypes()
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.MetadataBuilder.BuildTypes()
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.MetadataBuilder.BuildModule()
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.MetadataBuilder.BuildMetadata()
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.ModuleWriter.<>c.<BuildMetadata>b__2_0(MetadataBuilder builder, MetadataReader _)
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.ModuleDefinition.Read[TItem,TRet](TItem item, Func`3 read)
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.ModuleWriter.BuildMetadata(ModuleDefinition module, MetadataBuilder metadata)
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.ModuleWriter.Write(ModuleDefinition module, Disposable`1 stream, WriterParameters parameters)
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.ModuleWriter.WriteModule(ModuleDefinition module, Disposable`1 stream, WriterParameters parameters)
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.ModuleDefinition.Write(String fileName, WriterParameters parameters)
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Mono.Cecil.AssemblyDefinition.Write(String fileName)
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Bolero.Build.BoleroTask.StripFile(String f)
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error :    at Bolero.Build.BoleroTask.Execute()
3>C:\my\bolero\src\Bolero.Build\Bolero.Build.targets(13,5): error : Failed to resolve assembly: 'mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e'

It seems Cecil looks up dependencies incorrectly when writing the modified assembly. Not sure why it does it differently when building from VS or from command line.

Templating hot reload

Add hot reloading for HTML templates. This should be as seamless as possible.

  • Server side middleware which watches HTML files and sends updated source through a websocket. (SignalR? plain websocket? whichever is simplest)

  • Client side using the same HtmlAgilityPack-based code as the type provider to parse this file and convert it into Nodes.

  • Switching the client side between this mode of operation and normal rendering should be doable in a single small snippet that can be wrapped in #if DEBUG, eg maybe |> Program.withHotReload in ProgramComponent.

  • Ensure that all the relevant components are re-rendered when reload happens.

  • Ensure that there is minimal to no overhead (such as extra download size) when not using this feature. This might mean implementing it in a separate assembly.

Calling Swagger/OpenAPI backend API with GET, PATCH etc.

Great library, thinking of using it for a new project!!

One question though - the documentation contains only samples about Remoting, which states

"Remote calls are POST requests to the function's URL. Arguments and return values are automatically serialized to JSON.

Can I call "normal" Swagger/OpenAPI backend endpoints, with verbs like GET and PATCH as well? Any examples/pointers are appreciated!

Client Startup: services.AddRemoting defaults to ServerRemotingExtensions.AddRemoting, causing runtime exception

I ran into this issue today while trying to add remoting to the Bolero client side project. It seems that when I call services.AddRemoting(), it calls one of the ServerRemotingExtensions methods, and produces the following runtime error

System.ArgumentException: 'Cannot instantiate implementation type 'Bolero.Remoting.IRemoteHandler' for service type 'Bolero.Remoting.IRemoteHandler'.'

Sample code:

namespace RemoteTest.Client

open Microsoft.AspNetCore.Blazor.Builder
open Microsoft.AspNetCore.Blazor.Hosting
open Microsoft.Extensions.DependencyInjection
open Bolero.Remoting

type Startup() =

    member __.ConfigureServices(services: IServiceCollection) =
        // Causes a runtime error
        services.AddRemoting() |> ignore
        // Works as expected
        ClientRemotingExtensions.AddRemoting(services) |> ignore

    member __.Configure(app: IBlazorApplicationBuilder) =
        app.AddComponent<Main.MyApp>("#main")

module Program =

    [<EntryPoint>]
    let Main args =
        BlazorWebAssemblyHost.CreateDefaultBuilder()
            .UseBlazorStartup<Startup>()
            .Build()
            .Run()
        0

Templating: hole attribute should take obj

If a hole is always used as the full value of an attribute, ie foo="${Hole}", then it should be filled with obj rather than string. This is particularly useful for boolean attributes such as disabled.

Server side hosting doesn't work

I want to have a way to debug client side code using server side hosting of Blazor.

https://github.com/fsbolero/Bolero/tree/master/tests/Server seems to be doing the setup I'm looking for, but unfortunately it doesn't work.

I've built the project and run Server.exe. Navigated to http://localhost:5000 and I'm getting HTTP 404 which I also see in the log:

info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/1.1 GET http://localhost:5000/
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
      Executing endpoint 'Fallback {*path:nonfile}'
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint 'Fallback {*path:nonfile}'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished in 0.7887000000000001ms 404

P.S. Remoting.Server seems to be working fine.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.