Can't use C# 9.0 Record for actor method return type
See original GitHub issueExpected 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:
- Created 2 years ago
- Reactions:2
- Comments:8 (3 by maintainers)
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?@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?