ServiceStack / Issues

Issue Tracker for the commercial versions of ServiceStack
11 stars 8 forks source link

Behavior of TypeSerializer.SerializeToStream is affected by previous calls #761

Closed cosborne83 closed 3 years ago

cosborne83 commented 3 years ago

The behavior of TypeSerializer.SerializeToStream(object, Type, Stream) with regards the inclusion of type information ("__type") appears to be dependent on whether or not SerializeToStream<T>(T, stream) has been called first.

Using the latest ServiceStack.Text NuGet version (v5.11.0)

Setup code:

public interface IFoo
{
    string Property { get; }
}

public class FooA : IFoo
{
    public string Property { get; set; } = "A";
}

public class Test
{
    // Serialize using TypeSerializer.SerializeToStream<T>(T, Stream)
    public static void SerializeToStream1(IFoo item)
    {
        using (var stream = new MemoryStream())
        {
            TypeSerializer.SerializeToStream(item, stream);
            Console.WriteLine("SerializeToStream<T>(T, Stream):\n{0}\n", Encoding.UTF8.GetString(stream.GetBuffer(), 0, (int)stream.Length));
        }
    }

    // Serialize using TypeSerializer.SerializeToStream(object, Type, Stream)
    public static void SerializeToStream2(IFoo item)
    {
        using (var stream = new MemoryStream())
        {
            TypeSerializer.SerializeToStream(item, item.GetType(), stream);
            Console.WriteLine("SerializeToStream(object, Type, Stream):\n{0}\n", Encoding.UTF8.GetString(stream.GetBuffer(), 0, (int)stream.Length));
        }
    }
}

Given the above setup code, I would expect the output of SerializeToStream1 and SerializeToStream2 to be consistent when called on a given instance, however that is not the case:

Calling:

var a = new FooA();
Test.SerializeToStream1(a);
Test.SerializeToStream2(a);

Outputs:

SerializeToStream(T, Stream): {Property:A}

SerializeToStream(object, Type, Stream): {__type:"Test.FooA, Test",Property:A}

But calling:

var a = new FooA();
Test.SerializeToStream2(a);
Test.SerializeToStream1(a);

Outputs:

SerializeToStream(object, Type, Stream): {Property:A}

SerializeToStream(T, Stream): {Property:A}

The above shows that TypeSerializer.SerializeToStream(object, Type, Stream) only includes type information if TypeSerializer.SerializeToStream<T>(T, Stream) is called first, which does not seem correct.

Layoric commented 3 years ago

Thanks for reporting @cosborne83 , I used your code to replicate the issue in a test and applied a fix. This should be resolved with the latest release of v5.11.1 that's now available on MyGet.