F# host: Could not find an implementation for interface OrleansDashboard.IDashboardGrain - C# host ok
Unable to host silo in F# console project. C# console project works fine. Please see attached minimal repo.
Need to host in F# due to other F# frameworks (e.g. for web dev) required for the application.
Issue is with the 7.x version. This was not an issue with the 3.x.x version of Orleans.
F# hosting works if 'UseDashboard' is commented out.
Error seen:
fail: Orleans.Runtime.SiloLifecycleSubject[100450]
Orleans.Hosting.SiloBuilderStartupExtensions+StartupTask failed to start due to errors at stage Active (20000)
System.ArgumentException: Could not find an implementation for interface OrleansDashboard.IDashboardGrain
at Orleans.GrainInterfaceTypeToGrainTypeResolver.GetGrainType(GrainInterfaceType interfaceType) in /_/src/Orleans.Core/Core/GrainInterfaceTypeToGrainTypeResolver.cs:line 149
at Orleans.GrainFactory.GetGrain(Type interfaceType, IdSpan grainKey, String grainClassNamePrefix) in /_/src/Orleans.Core/Core/GrainFactory.cs:line 214
at Orleans.GrainFactory.GetGrain[TGrainInterface](Int64 primaryKey, String grainClassNamePrefix) in /_/src/Orleans.Core/Core/GrainFactory.cs:line 52
at OrleansDashboard.Dashboard.ActivateDashboardGrainAsync()
at OrleansDashboard.Dashboard.Execute(CancellationToken cancellationToken)
at Orleans.Runtime.SiloLifecycleSubject.MonitoredObserver.OnStart(CancellationToken ct) in /_/src/Orleans.Runtime/Lifecycle/SiloLifecycleSubject.cs:line 134
f
Update: I set <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> in the C# host project and found that there are 'generated' files for Dashboard grain serialization.
No source is generated for F# so maybe that's the reason for the error. However, not sure what is the solution other than maybe support for F# code generation.
After a little more digging, I found that adding parts of C# generated code - namely assembly attributes - to F# host, fixed this issue. 'Program.fs' is now as follows:
open Microsoft.Extensions.Hosting
open Orleans
open Orleans.Hosting
Host.CreateDefaultBuilder()
.UseOrleans(fun siloBuilder ->
siloBuilder
.UseDashboard()
.UseLocalhostClustering()
.AddMemoryGrainStorage("store") |> ignore)
.RunConsoleAsync()
|> Async.AwaitTask
|> Async.RunSynchronously
module Load =
//[<assembly: Orleans.ApplicationPartAttribute("SiloCS")>]
[<assembly: Orleans.ApplicationPartAttribute("GrainsCodeGen")>]
[<assembly: Orleans.ApplicationPartAttribute("Orleans.Core.Abstractions")>]
[<assembly: Orleans.ApplicationPartAttribute("Orleans.Serialization")>]
[<assembly: Orleans.ApplicationPartAttribute("Orleans.Core")>]
[<assembly: Orleans.ApplicationPartAttribute("Orleans.Persistence.Memory")>]
[<assembly: Orleans.ApplicationPartAttribute("Orleans.Runtime")>]
[<assembly: Orleans.ApplicationPartAttribute("Orleans.Reminders")>]
[<assembly: Orleans.ApplicationPartAttribute("OrleansDashboard.Core")>]
[<assembly: Orleans.ApplicationPartAttribute("OrleansDashboard")>]
//[<assembly: global::Orleans.Serialization.Configuration.TypeManifestProviderAttribute(typeof(OrleansCodeGen.SiloCS.Metadata_SiloCS))]
()
I will use this as a workaround while waiting for the 'official' fix or recommendation.
Also not sure what the TypeManifestProvider attribute does and will a lack of it cause issues later on?
linking reminders issue #8125. The workaround solution will likely work for the reminder table issue also
Thanks legend. Nice one for this
I spent past three days looking for even a trivial end-to-end F#-only example of how to use Orleans with F#, and I am hitting several issues including this one. Seems like F# is low priority for Orleans. What would be recommended solution - shall I set up mixed C# / F# project, with host written in C#? @fwaris what are your experiences?
The code generator that Orleans uses only knows how to output C# code, so you need C# in your app somewhere. The host process is a good place for it since it's the top level that references all assemblies, but it's not strictly required that it's C#. An alternative is to do what @fwaris showed above, where you add an attribute(s) pointing to the C# assembly/assemblies. With that, you can follow the rest of the approach outlined in the F# sample: https://github.com/dotnet/samples/tree/main/orleans/FSharpHelloWorld. Having a fully F# sample, where all app code is written in F# and the only C# project is the one receiving the generated code, would be very welcome.
I had to put a minimal C# library in the solution for the code gen to work.
Below is a sample (prob. now out-of-date) that might help.
https://github.com/fwaris/OrleansKafkaSample
Thanx @fwaris ! I took some time to clean up your project and to strip it down to something that would be basic sample project for people who would like to use Orleans with F#. If you have a minute or two, I would be grateful if you could glance over the code to verify I am not making anything stupid - I am yet starting with Orleans.
@ReubenBond if you can glance over the code and verify this is the correct / best-practices way of setting up Orleans, that would be awesome.
Thanx!
https://github.com/DejanMilicic/OrleansFsharp
@DejanMilicic sure I can take a quick look at it
looks good. nice and clean.
@fwaris I am now proceeding further (in my private repo) and refactoring code to be more F# style. As part of that refactoring, I am introducing messages in the form of discriminated union. Call to grain succeeds, but received message is null. Clearly, it is a serialization problem. I tried various things in past few days, but I did not manage to fix it.
Can you point me to a working example where F# type is successfully serialized and deserialized in the context of Orleans? Thanx!
in my prod app I think I side-stepped the problem by not using discriminated unions, as I was running into serialization issues also.
(This seriously affects F# programming style!)
@ReubenBond hopefully we can get F# discriminated unions working again see https://github.com/dotnet/orleans/issues/9258
The thread you linked provides a workaround, @fwaris - adding the following to the F# project fixes it:
[<InternalsVisibleTo("Host")>]
do ()
I tested the fix using the repro project. I'm not sure why it's occurring, or what changed. The code generator should at least error out instead of ignoring the internal members silently as it seems to be doing today.
thanks @ReubenBond, I was not aware of this. @DejanMilicic can you please try the fix and let us know
I'm not sure we can fix this without mandating InternalsVisibleTo, which should be documented in the sample. We could check for it and error if it's not set. I debugged through the case, and we cannot even see the underlying field from the source generator:
// Without InternalsVisibleTo:
Length = 2
[0]: {UnitTests.FSharpTypes.HelloWorldResult.Completed.Item.get}
[1]: {UnitTests.FSharpTypes.HelloWorldResult.Completed.Item}
Results View: Expanding the Results View will enumerate the IEnumerable
// With InternalsVisibleTo:
Length = 4
[0]: {UnitTests.FSharpTypes.HelloWorldResult.Completed.item}
[1]: {UnitTests.FSharpTypes.HelloWorldResult.Completed.Completed(string)}
[2]: {UnitTests.FSharpTypes.HelloWorldResult.Completed.Item.get}
[3]: {UnitTests.FSharpTypes.HelloWorldResult.Completed.Item}
I managed to get everything working with latest version of .NET and latest version of Orleans. Project is updated with detailed instructions in README https://github.com/DejanMilicic/OrleansFsharp
@fwaris I will be grateful for any suggestions you might have @ReubenBond what would be the best way to help fellow F# developers? Would you be okay with expansion of Samples with this project and also with polished up version of https://github.com/DejanMilicic/orleans-fsharp-dotnet9 that showcases similar scenario, but with whole Host project in C# (essentially, interoperability of C# and F# on Orleans project where some or all of the grains can be in F#)?
@DejanMilicic
Would you be okay with expansion of Samples with this project and also with polished up version of https://github.com/DejanMilicic/orleans-fsharp-dotnet9 that showcases similar scenario, but with whole Host project in C# (essentially, interoperability of C# and F# on Orleans project where some or all of the grains can be in F#)?
That would be fantastic. If you open a PR against the dotnet/samples repo, we'll merge it. A docs page would also be very useful for F# developers, if you're up for it, maybe under the 'quickstarts' section: https://github.com/dotnet/docs/tree/main/docs/orleans/quickstarts
Hello everyone, is there any documentation that explains this C# code generation process? And were there any updates regarding F# support?
Update:
I created a project that implements the quickstart UrlShortener project in F# based on @DejanMilicic's sample project:
- https://github.com/64J0/orleans-fsharp--url-shortener