question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Can't use C# 9.0 Record for actor method return type

See original GitHub issue

Expected Behavior

I would like to use a record as a return type for an actor method.

Actual Behavior

ActorInvokeException: Type ‘Chronos.Actors.EquipmentAssignments’ cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. Alternatively, you can ensure that the type is public and has a parameterless constructor - all public members of the type will then be serialized, and no attributes will be required.

Here is the record definition:

    public record EquipmentActorState(Guid Id, Guid SolarSystemId, string OwnerTypeId, EquipmentAssignments EquipmentAssignments, List<EquipmentSwapRequest> SwapRequests);
    public record EquipmentAssignments(Guid Id, string ShipTypeId, Dictionary<int, EquipmentSlot> EquipmentSlots, Dictionary<Guid, EquipmentReference> AvailableEquipment);
    public record EquipmentSlot(EquipmentSlotType Type, Guid? CurrentlyAssignedEquipment);
    public record EquipmentReference(Guid Id, string Type, EquipmentSlotType SlotType, int? AssignedSlotId);

//... Inside the actor class definition
    public async Task<EquipmentAssignments?> GetEquipmentDetails()
    {
         var state = await StateManager.GetStateAsync<EquipmentActorState>("state");
         return state.EquipmentAssignments; // <-- this cannot be serialized?
    }

It fails on this line in the dotnet-sdk: https://github.com/dapr/dotnet-sdk/blob/master/src/Dapr.Actors/Communication/ActorMessageBodyDataContractSerializationProvider.cs#L206

Which throws this exception:

Exception has occurred: CLR/System.Runtime.Serialization.InvalidDataContractException
Exception thrown: 'System.Runtime.Serialization.InvalidDataContractException' in System.Private.DataContractSerialization.dll: 'Type 'Chronos.Actors.EquipmentAssignments' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. Alternatively, you can ensure that the type is public and has a parameterless constructor - all public members of the type will then be serialized, and no attributes will be required.'
   at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.ThrowInvalidDataContractException(String message, Type type)
   at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.CreateDataContract(Type type)
   at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.CreateDataContract(Int32 id, RuntimeTypeHandle typeHandle, Type type)
   at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.GetDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type)
   at System.Runtime.Serialization.DataContract.GetDataContract(RuntimeTypeHandle typeHandle, Type type, SerializationMode mode)
   at System.Runtime.Serialization.XmlObjectSerializerContext.GetDataContract(RuntimeTypeHandle typeHandle, Type type)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContextComplex.InternalSerializeWithSurrogate(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContextComplex.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerializeReference(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.ClassDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiType(XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle objectTypeHandle, Type objectType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContextComplex.InternalSerializeWithSurrogate(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContextComplex.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerializeReference(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.ClassDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
   at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
   at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
   at System.Runtime.Serialization.XmlObjectSerializer.WriteObject(XmlDictionaryWriter writer, Object graph)
   at Dapr.Actors.Communication.ActorMessageBodyDataContractSerializationProvider.MemoryStreamMessageBodySerializer`2.Dapr.Actors.Communication.IActorResponseMessageBodySerializer.Serialize(IActorResponseMessageBody actorResponseMessageBody) in /dotnet-sdk/src/Dapr.Actors/Communication/ActorMessageBodyDataContractSerializationProvider.cs:line 206

Steps to Reproduce the Problem

Return a Record type from an actor and call it using the dotnet-sdk

Release Note

RELEASE NOTE:

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:2
  • Comments:8 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
onionhammercommented, Jan 3, 2023

Bumping… cant seem to use them for arguments either. Easily system.text.json serializable stuff just doesnt work with whatever voodoo ActorMessageBodyDataContractSerializationProvider is doing… just stop doing voodoo and voila, things will work better.

Why provide ActorProxyOptions.JsonSerializerOptions? What is that for? Is it ignored?

0reactions
shivamkm07commented, Jun 15, 2023

@onionhammer PR #1073 seems to add Json Serialization capability to the actor response serialization. So would that resolve this issue of using Records as return type?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Records in C# 9 - InfoQ
Record types have a compiler-generated ToString method that returns the names and values of public properties and fields in an instance.
Read more >
What's new in C# 9.0 - C# Guide
Record types have a compiler-generated ToString method that displays the names and values of public properties and fields. The ToString method ...
Read more >
C# 9.0 on the record - .NET Blog
The with-expression works by actually copying the full state of the old object into a new one, then mutating it according to the...
Read more >
How to work with record types in C# 9
Because a record type is immutable, it is thread-safe and cannot mutate or change after it has been created. You can initialize a...
Read more >
Enabling and using C# 9 features on older and “unsupported ...
This category includes features such as default interface methods from C# 8 and covariant return types in C# 9. The second category instead ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found