Orleans: System.TypeAccessException: Named type "..." is invalid: Type string "..." cannot be resolved.

Created on 12 Mar 2018  路  2Comments  路  Source: dotnet/orleans

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()<---

Most helpful comment

@alexandrnikitin there are 3 ways you can fix this:

  1. The project containing MakeRideAction can include Microsoft.Orleans.OrleansCodeGenerator.Build and Microsoft.Orleans.Core.Abstractions packages.

  2. 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

All 2 comments

@alexandrnikitin there are 3 ways you can fix this:

  1. The project containing MakeRideAction can include Microsoft.Orleans.OrleansCodeGenerator.Build and Microsoft.Orleans.Core.Abstractions packages.

  2. 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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pherbel picture pherbel  路  4Comments

galvesribeiro picture galvesribeiro  路  4Comments

jt4000 picture jt4000  路  3Comments

danvanderboom picture danvanderboom  路  3Comments

guopenglun picture guopenglun  路  3Comments