I am basically trying to replicate this tutorial https://docs.microsoft.com/en-us/aspnet/core/tutorials/signalr?view=aspnetcore-2.1&tabs=visual-studio-code.
In Program.fs I have:
let configureServices (services : IServiceCollection) =
services.AddCors() |> ignore
services.AddGiraffe() |> ignore
services.AddSignalR() |> ignore
let configureApp (app : IApplicationBuilder) =
let env = app.ApplicationServices.GetService<IHostingEnvironment>()
(match env.IsDevelopment() with
| true -> app.UseDeveloperExceptionPage()
| false -> app.UseGiraffeErrorHandler errorHandler)
.UseCors(configureCors)
.UseStaticFiles()
.UseSignalR(fun routes -> routes.MapHub<ChatHub>(PathString("/chatHub")) |> ignore)
.UseGiraffe(webApp)
And in Services/ChatHub.fs:
module Hubs
open Microsoft.AspNetCore.SignalR
open FSharp.Control.Tasks.ContextInsensitive
type ChatHub() =
inherit Hub()
member x.SendMessage user msg =
task {
do! x.Clients.All.SendAsync("ReceiveMessage", user, msg)
}
Upon the attempt of running the app, the exception I am getting is:
Application startup exception: System.ArgumentException: Type a contains generic parameters
Parameter name: type
at System.Dynamic.Utils.TypeUtils.ValidateType(Type type, String paramName, Int32 index)
at System.Dynamic.Utils.TypeUtils.ValidateType(Type type, String paramName, Boolean allowByRef, Boolean allowPointer)
at System.Linq.Expressions.Expression.Convert(Expression expression, Type type, MethodInfo method)
at Microsoft.Extensions.Internal.ObjectMethodExecutor.GetExecutor(MethodInfo methodInfo, TypeInfo targetTypeInfo)
at Microsoft.Extensions.Internal.ObjectMethodExecutor..ctor(MethodInfo methodInfo, TypeInfo targetTypeInfo, Object[] parameterDefaultValues)
at Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher`1.DiscoverHubMethods()
at Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher`1..ctor(IServiceScopeFactory serviceScopeFactory, IHubContext`1 hubContext, IOptions`1 hubOptions, IOptions`1 globalHubOptions, ILogger`1 logger)
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProvider provider)
at Microsoft.Extensions.Internal.ActivatorUtilities.GetServiceOrCreateInstance[T](IServiceProvider provider)
at Microsoft.AspNetCore.Connections.ConnectionBuilderExtensions.UseConnectionHandler[TConnectionHandler](IConnectionBuilder connectionBuilder)
at Microsoft.AspNetCore.SignalR.HubRouteBuilder.<>c__3`1.<MapHub>b__3_0(IConnectionBuilder builder)
at Microsoft.AspNetCore.Http.Connections.ConnectionsRouteBuilder.MapConnections(PathString path, HttpConnectionDispatcherOptions options, Action`1 configure)
at Microsoft.AspNetCore.SignalR.HubRouteBuilder.MapHub[THub](PathString path, Action`1 configureOptions)
at Microsoft.AspNetCore.SignalR.HubRouteBuilder.MapHub[THub](PathString path)
at [email protected](HubRouteBuilder routes) in /Users/maciej.sitko/Documents/Tut/GiraffeSample/src/GiraffeSample/Program.fs:line 96
at Microsoft.AspNetCore.Builder.ConnectionsAppBuilderExtensions.UseConnections(IApplicationBuilder app, Action`1 configure)
at Microsoft.AspNetCore.Builder.SignalRAppBuilderExtensions.UseSignalR(IApplicationBuilder app, Action`1 configure)
at GiraffeSample.App.configureApp(IApplicationBuilder app) in /Users/maciej.sitko/Documents/Tut/GiraffeSample/src/GiraffeSample/Program.fs:line 93
at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
Unhandled Exception: System.ArgumentException: Type a contains generic parameters
Parameter name: type
at System.Dynamic.Utils.TypeUtils.ValidateType(Type type, String paramName, Int32 index)
at System.Dynamic.Utils.TypeUtils.ValidateType(Type type, String paramName, Boolean allowByRef, Boolean allowPointer)
at System.Linq.Expressions.Expression.Convert(Expression expression, Type type, MethodInfo method)
at Microsoft.Extensions.Internal.ObjectMethodExecutor.GetExecutor(MethodInfo methodInfo, TypeInfo targetTypeInfo)
at Microsoft.Extensions.Internal.ObjectMethodExecutor..ctor(MethodInfo methodInfo, TypeInfo targetTypeInfo, Object[] parameterDefaultValues)
at Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher`1.DiscoverHubMethods()
at Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher`1..ctor(IServiceScopeFactory serviceScopeFactory, IHubContext`1 hubContext, IOptions`1 hubOptions, IOptions`1 globalHubOptions, ILogger`1 logger)
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProvider provider)
at Microsoft.Extensions.Internal.ActivatorUtilities.GetServiceOrCreateInstance[T](IServiceProvider provider)
at Microsoft.AspNetCore.Connections.ConnectionBuilderExtensions.UseConnectionHandler[TConnectionHandler](IConnectionBuilder connectionBuilder)
at Microsoft.AspNetCore.SignalR.HubRouteBuilder.<>c__3`1.<MapHub>b__3_0(IConnectionBuilder builder)
at Microsoft.AspNetCore.Http.Connections.ConnectionsRouteBuilder.MapConnections(PathString path, HttpConnectionDispatcherOptions options, Action`1 configure)
at Microsoft.AspNetCore.SignalR.HubRouteBuilder.MapHub[THub](PathString path, Action`1 configureOptions)
at Microsoft.AspNetCore.SignalR.HubRouteBuilder.MapHub[THub](PathString path)
at [email protected](HubRouteBuilder routes) in /Users/maciej.sitko/Documents/Tut/GiraffeSample/src/GiraffeSample/Program.fs:line 96
at Microsoft.AspNetCore.Builder.ConnectionsAppBuilderExtensions.UseConnections(IApplicationBuilder app, Action`1 configure)
at Microsoft.AspNetCore.Builder.SignalRAppBuilderExtensions.UseSignalR(IApplicationBuilder app, Action`1 configure)
at GiraffeSample.App.configureApp(IApplicationBuilder app) in /Users/maciej.sitko/Documents/Tut/GiraffeSample/src/GiraffeSample/Program.fs:line 93
at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
at GiraffeSample.App.main(String[] _arg1) in /Users/maciej.sitko/Documents/Tut/GiraffeSample/src/GiraffeSample/Program.fs:line 112
Do you know what is the possible cause for this?
Did you figure out what the problem was?
Ah yes, it was not Giraffe per se but how F# plays with SignalR. Stack traces seems very vague and doesn't explain why is it happening, but adding type annotations here:
member x.SendMessage (user: string, msg: string) =
task {
do! x.Clients.All.SendAsync("ReceiveMessage", user, msg)
}
Fixes the issue.
I am encountering this same issue. No solution for it yet on my end and this is with C#.
I found the root issue in my case. You cannot seem to have generic public methods on SignalR hubs. SignalR will attempt to do some internal registration for public methods it seems and this will fail when they are generic.
In my case, the solution was to just make my interface method implementation explicit. If you have generic method members just make them private or something. That should work too.
Better warnings/errors should be thrown when this occurs in my opinion!
Obviously this isn't an issue with Giraffe. But with ASP Core SignalR itself. However, seemed relevant to post here since this is where Google brings you.
I'll open an issue on the ASP Core github about this too.
Just a note here (because FSharp-Giraffe-SignalR combination is not well documented)... You can also to strongly typed hub:
type IMessageToClient =
abstract NotifyDeal : string -> Task
type SignalHub() as this =
inherit Hub<IMessageToClient>()
member __.BuyStocks (company:string) (amount:int) =
//...
this.Clients.All.NotifyDeal "New deal was done!"
Sadly I have not found support to EnableJavaScriptProxies or how to generate proxies manually with a tool like signalr.exe was.
Most helpful comment
I found the root issue in my case. You cannot seem to have generic public methods on SignalR hubs. SignalR will attempt to do some internal registration for public methods it seems and this will fail when they are generic.
In my case, the solution was to just make my interface method implementation explicit. If you have generic method members just make them private or something. That should work too.
Better warnings/errors should be thrown when this occurs in my opinion!
Obviously this isn't an issue with Giraffe. But with ASP Core SignalR itself. However, seemed relevant to post here since this is where Google brings you.
I'll open an issue on the ASP Core github about this too.