I believe I encounter a bug. It seems Orleans doesn't work well with generic type that is located in another project. Could be related to #4012
I've prepared a minimal repro project for the case: https://github.com/alexandrnikitin/orleans-repro-4188
To reproduce:
cd \samples\GoogleHashcode2018
>BuildAndRun.ps1
Observe Client console app output. The following exception appears:
System.AggregateException: One or more errors occurred. (Named type "DMCTS.Grains.NodeView`1<Rides.MakeRideAction>" is invalid: Type string "Rides.MakeRideAction" cannot be resolved.) ---> System.TypeAccessException: Named type "DMCTS.Grains.NodeView`1<Rides.MakeRideAction>" is invalid: Type string "Rides.MakeRideAction" cannot be resolved.
at Orleans.Serialization.BinaryTokenStreamReaderExtensinons.ReadSpecifiedTypeHeader(IBinaryTokenStreamReader this, SerializationManager serializationManager)
at Orleans.Serialization.SerializationManager.DeserializeInner(Type expected, IDeserializationContext context)
at Orleans.Serialization.BuiltInTypes.DeserializeOrleansResponse(Type expected, IDeserializationContext context)
at Orleans.Serialization.SerializationManager.DeserializeInner(Type expected, IDeserializationContext context)
at Orleans.Serialization.SerializationManager.Deserialize(Type t, IBinaryTokenStreamReader stream)
at Orleans.Runtime.Message.GetDeserializedBody(SerializationManager serializationManager)
at Orleans.Runtime.GrainReferenceRuntime.ResponseCallback(Message message, TaskCompletionSource`1 context)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Orleans.OrleansTaskExtentions.<<ToTypedTask>g__ConvertAsync4_0>d`1.MoveNext()
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
at Rides.Client.Program.<DoClientWork>d__3.MoveNext() in C:\projects\my\DistributedMonteCarloTreeSearch.NET\samples\GoogleHashcode2018\Rides.Client\Program.cs:line 81
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Rides.Client.Program.<RunMainAsync>d__1.MoveNext() in C:\projects\my\DistributedMonteCarloTreeSearch.NET\samples\GoogleHashcode2018\Rides.Client\Program.cs:line 26
---> (Inner Exception #0) System.TypeAccessException: Named type "DMCTS.Grains.NodeView`1<Rides.MakeRideAction>" is invalid: Type string "Rides.MakeRideAction" cannot be resolved.
at Orleans.Serialization.BinaryTokenStreamReaderExtensinons.ReadSpecifiedTypeHeader(IBinaryTokenStreamReader this, SerializationManager serializationManager)
at Orleans.Serialization.SerializationManager.DeserializeInner(Type expected, IDeserializationContext context)
at Orleans.Serialization.BuiltInTypes.DeserializeOrleansResponse(Type expected, IDeserializationContext context)
at Orleans.Serialization.SerializationManager.DeserializeInner(Type expected, IDeserializationContext context)
at Orleans.Serialization.SerializationManager.Deserialize(Type t, IBinaryTokenStreamReader stream)
at Orleans.Runtime.Message.GetDeserializedBody(SerializationManager serializationManager)
at Orleans.Runtime.GrainReferenceRuntime.ResponseCallback(Message message, TaskCompletionSource`1 context)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Orleans.OrleansTaskExtentions.<<ToTypedTask>g__ConvertAsync4_0>d`1.MoveNext()<---
@alexandrnikitin there are 3 ways you can fix this:
The project containing MakeRideAction can include Microsoft.Orleans.OrleansCodeGenerator.Build and Microsoft.Orleans.Core.Abstractions packages.
The client/silo projects can have an assembly level attribute to instruct the code generator to generate code for Rides also, like so:
```C#
[assembly: KnownAssembly(typeof(Rides.MakeRideAction))]
// on the builder:
.ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(ITreeGrain<>).Assembly))
.ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(NodeView<>).Assembly))
.ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(Program).Assembly))
3. You can generate code for `Rides` during startup by installing `Microsoft.Orleans.OrleansCodeGenerator` into the client/silo and using `WithCodeGeneration()` on both client and silo during configuration time, like so:
```C#
.ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(MakeRideAction).Assembly).WithCodeGeneration())
This requires that Rides includes Microsoft.Orleans.Core.Abstractions, since we filter it out otherwise.
Assuming you don't want to modify Rides.csproj, your best option out of these is the second: use KnownAssembly to generate code into a different project (you could also generate it into a special purpose project and then include that using ApplicationParts, or generate it into your interfaces project).
Hope that helps
Great! It helped! Thank you for the prompt response.
Most helpful comment
@alexandrnikitin there are 3 ways you can fix this:
The project containing
MakeRideActioncan includeMicrosoft.Orleans.OrleansCodeGenerator.BuildandMicrosoft.Orleans.Core.Abstractionspackages.The client/silo projects can have an assembly level attribute to instruct the code generator to generate code for
Ridesalso, like so:```C#
[assembly: KnownAssembly(typeof(Rides.MakeRideAction))]
// on the builder:
.ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(ITreeGrain<>).Assembly))
.ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(NodeView<>).Assembly))
.ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(Program).Assembly))
This requires that Rides includes
Microsoft.Orleans.Core.Abstractions, since we filter it out otherwise.Assuming you don't want to modify
Rides.csproj, your best option out of these is the second: useKnownAssemblyto generate code into a different project (you could also generate it into a special purpose project and then include that using ApplicationParts, or generate it into your interfaces project).Hope that helps