Skip to content

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

@LukePammant

Description

@LukePammant

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:

Metadata

Metadata

Labels

P1kind/bugSomething isn't working

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions