Skip to content

Orleans serializer is unable to handle correctly private fields of classes defined in some specific assemblies #9265

@mhadhbi

Description

@mhadhbi

Library name and version
Microsoft.Orleans.Serialization 9.0.1, 7.2.6 (and maybe other versions).

Bug description
We noticed that the Orleans serializer is unable to serialize correctly private fields of classes that are defined in an assembly with a single to Orleans (Microsoft.Orleans.Serialization.Abstractions NuGet package).

Here is an example of a class that cannot be handled by the serializer:

[GenerateSerializer]
public class MotorBike
{
    [Id(0)]
    private readonly string brand;

    [Id(1)]
    private readonly string model;

    public MotorBike(string brand, string model)
    {
        this.brand = brand;
        this.model = model;
    }

    public string Brand => this.brand;
    public string Model => this.model;
}

Reproduction Steps
This repository is containing the following unit test that can be used to reproduce the bug:

[TestCaseSource(nameof(GetObjectsToCheck))]
public void ShouldSerializeAndDeserializeObject<T>(T @object)
{
    // Arrange
    var serializer = cluster!.ServiceProvider.GetRequiredService<Serializer>();

    // Act
    var binaryData = serializer.SerializeToArray(@object);
    var deserializedObject = serializer.Deserialize<T>(binaryData);

    // Assert
    deserializedObject.Should().BeEquivalentTo(@object);
}

private static IEnumerable<TestCaseData> GetObjectsToCheck()
{
    yield return new TestCaseData(new Plane(brand: "Airbus", model: "A350")); // class with private fields defined in the test assembly (✅ passed)
    yield return new TestCaseData(new Car(brand: "Alpine", model: "A110")); // class with protected fields defined in another assembly (✅ passed)
    yield return new TestCaseData(new MotorBike(brand: "Honda", model: "CB1000R")); // class with private fields defined in another assembly (❌ failed)
    yield return new TestCaseData(new Train(brand: "Alstom", model: "TGV M")); // class with public properties defined in another assembly (✅ passed)
}

The test case with MotorBike object failed with the following error message:

 ShouldSerializeAndDeserializeObject<MotorBike>(OrleansSerialization.Contracts.MotorBike)
   Source: SerializationTests.cs line 25
   Duration: 59 ms

  Message: 
Expected property deserializedObject.Brand to be "Honda", but found <null>.
Expected property deserializedObject.Model to be "CB1000R", but found <null>.

With configuration:
- Use declared types and members
- Compare enums by value
- Compare tuples by their properties
- Compare anonymous types by their properties
- Compare records by their members
- Include non-browsable members
- Match member by name (or throw)
- Be strict about the order of items in byte arrays
- Without automatic conversion.


  Stack Trace: 
LateBoundTestFramework.Throw(String message)
TestFrameworkProvider.Throw(String message)
CollectingAssertionStrategy.ThrowIfAny(IDictionary`2 context)
AssertionScope.Dispose()
EquivalencyValidator.AssertEquality(Comparands comparands, EquivalencyValidationContext context)
ObjectAssertions`2.BeEquivalentTo[TExpectation](TExpectation expectation, Func`2 config, String because, Object[] becauseArgs)
ObjectAssertions`2.BeEquivalentTo[TExpectation](TExpectation expectation, String because, Object[] becauseArgs)
SerializationTests.ShouldSerializeAndDeserializeObject[T](T object) line 36

Workaround
We are able to circumvent the problem by changing the visibility of fields in the class to protected. This is clearly not an ideal solution for us.

Could you please take a look ?

Regards,
Ahmed

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions