dotnet / orleans

Cloud Native application framework for .NET
https://docs.microsoft.com/dotnet/orleans
MIT License
10.09k stars 2.03k forks source link

Problems when using your own code generator before Orleans code generator runs #9100

Open ant-10base opened 3 months ago

ant-10base commented 3 months ago

I've got an Orleans 8.x project, I've recently introduced a custom code generator using Roslyn which works great but unfortunately despite adding the [GenerateSerializer] attribute it appears Orleans doesnt pick up on it.

The end result is I get an error when using that because the copier is missing

Orleans.Serialization.CodecNotFoundException: Could not find a copier for type Employee.Domain.Aggregate.State.Events.AddFullNameEvent. at Orleans.Serialization.Serializers.CodecProvider.ThrowCopierNotFound(Type type) in /_/src/Orleans.Serialization/Serializers/CodecProvider.cs:line 674 at Orleans.Serialization.Serializers.CodecProvider.GetDeepCopier(Type fieldType) in /_/src/Orleans.Serialization/Serializers/CodecProvider.cs:line 327 at Orleans.Serialization.Cloning.CopyContext.DeepCopy[T](T value) in /_/src/Orleans.Serialization/Cloning/IDeepCopier.cs:line 263 at Orleans.Serialization.ServiceCollectionExtensions.CopierHolder1.DeepCopy(T original, CopyContext context) in //src/Orleans.Serialization/Hosting/ServiceCollectionExtensions.cs:line 198 at Orleans.Serialization.Codecs.DictionaryCopier2.DeepCopy(Dictionary2 input, CopyContext context) in //src/Orleans.Serialization/Codecs/DictionaryCodec.cs:line 177 at Orleans.Serialization.Cloning.IDeepCopier1.Orleans.Serialization.Cloning.IDeepCopier.DeepCopy(Object input, CopyContext context) in /_/src/Orleans.Serialization/Cloning/IDeepCopier.cs:line 123 at Orleans.Serialization.Cloning.CopyContext.DeepCopy[T](T value) in /_/src/Orleans.Serialization/Cloning/IDeepCopier.cs:line 263 at OrleansCodeGen.Employee.Domain.Aggregate.Proxy_IEmployeeAggregate.global::_10Base.Framework.Aggregates.IBaseAggregate.ExecuteCommand(ExecuteCommand arg0) in C:\projects\product_HRHarbour\src\Domain\Employee.Domain\Orleans.CodeGenerator\Orleans.CodeGenerator.OrleansSerializationSourceGenerator\Employee.Domain.orleans.g.cs:line 53 at _10Base.Framework.Commands.CommandHandler.ExecuteCommand[TIAggregate](PrimaryKey primaryKey, ExecuteCommand command) in C:\projects\product_HRHarbour\src\Framework\10Base.Framework\Commands\CommandHandler.cs:line 28 a

I've done something similar in Orleans 3.x and I had to use an intermediary project between the Roslyn code generator and the Orleans code generator but that doesnt appear to work in Orleans 8.x

ReubenBond commented 3 months ago

There's a similar issue here: https://github.com/dotnet/orleans/issues/8420 The ability to apply ordering to source generators is tracked here: https://github.com/dotnet/roslyn/issues/57239 I recall that there was a hack to impose ordering, maybe it's described in one of those issues or an issue linked from there. The trick with an intermediary assembly might be workable using the [GenerateCodeForDeclaringAssembly(Type)] attribute but note that there is currently an issue generating code for record types in external assemblies. Please let us know if you find a solution

ant-10base commented 2 months ago

So I tried again with an intermediary project (thinking that would work), so added in

[assembly: GenerateCodeForDeclaringAssembly(typeof(Employee.Domain.Aggregate.State.Events.AddIdEvent))]

but instead I get error CS0122: 'Proxy_IEmployeeAggregate' is inaccessible due to its protection level when building the intermediary project

If I dont use the new project it builds fine (even compiles and runs but then at runtime Orleans cannot find the copier for the AddIdEvent class, the original problem).

I cant see the file generated "Employee.Domain.Orleans.orleans.g.cs" thats throwing the CS0122

ant-10base commented 2 months ago

Ok so a bit more tweaking and now it works. Because I have some abstract classes that handle the Orleans implementation, and then another project that defines the more domain orientated code I think it clashed with the Orleans package references and subsequent code generation.

I've got my "framework" project to reference <PackageReference Include="Microsoft.Orleans.Runtime" Version="8.0.0" /> which my domain project references (including my own code generators), then using an intermediary project to reference that domain project which references <PackageReference Include="Microsoft.Orleans.Sdk" Version="8.0.0" /> and using the attributes [assembly: GenerateCodeForDeclaringAssembly(typeof(IEmployeeAggregate))] [assembly: GenerateCodeForDeclaringAssembly(typeof(BaseState<EmployeeProfile>))]

The only thing that is odd is I had some private fields which stopped working and had to make public which does make sense but I dont understand why they worked before.