Hyperion icon indicating copy to clipboard operation
Hyperion copied to clipboard

Hyperion failed with "Index was out of range" in `GetDeserializedObject` when payload has Duplicate Values

Open daniellittledev opened this issue 7 years ago • 1 comments

My payload contains data like this in an FSharp Record. The error goes away if the values if the values are different. Only occurs when preserve object refs is true.

    Section = Some "sd"
    SubDivision = Some "sd"

This is the exception.

$exception	{"Index was out of range. Must be non-negative and less than the size of the collection.\r\nParameter name: index"}	System.ArgumentOutOfRangeException

Here is the line that fails.

public class DeserializerSession
{
    ////
    public object GetDeserializedObject(int id)
    {
        return _objectById[id]; // <- here
    }
    ////

Stack Trace

>	Hyperion.dll!Hyperion.DeserializerSession.GetDeserializedObject(int id = 14) Line 66	C#
 	Hyperion.dll!Hyperion.ValueSerializers.ObjectReferenceSerializer.ReadValue(System.IO.Stream stream = {System.IO.MemoryStream}, Hyperion.DeserializerSession session = {Hyperion.DeserializerSession}) Line 34	C#
 	Hyperion.dll!Hyperion.Extensions.StreamEx.ReadObject(System.IO.Stream stream = {System.IO.MemoryStream}, Hyperion.DeserializerSession session = {Hyperion.DeserializerSession}) Line 172	C#

daniellittledev avatar May 30 '17 01:05 daniellittledev

Here's a failing test in F#, it looks like the root cause is the inclusion of the F# Map type in the Header type of the Payload record.

type Header = {
    Properties: Map<int,int>;
}

type Payload<'t> = 
    {
        Header: Header;
        Value: 't
    }
    override this.ToString() =
        "Envelope: " + this.Value.ToString()

type InnerType = {
    OneField : string option
    TwoField : string option 
}
type OuterType = {
    Something : InnerType
    FirstField : string option
    SecondField : string option 
    ThirdField : string option 
}

let inner = {
    OneField = Some "value"
    TwoField = Some "value"
}

let toSerialise = {
    Header = { Properties = Map.empty; }
    Value = inner
}

toSerialise |> Dump |> ignore 

let options = Hyperion.SerializerOptions(preserveObjectReferences = true)
let serialiser = Hyperion.Serializer(options)

let ``run test`` = 
    use inbound = new MemoryStream()
    serialiser.Serialize(toSerialise, inbound)
    inbound.Flush()
        
    use outbound = new MemoryStream(inbound.ToArray())
    let result = serialiser.Deserialize outbound
    
    result

``run test`` |> Dump |> ignore 

Ran in LinqPad, using the latest Hyperion from nuget

tvjames avatar May 30 '17 02:05 tvjames