Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
mhadhbi opened this issue Dec 9, 2024 · 1 comment

Comments

@mhadhbi
Copy link

mhadhbi commented Dec 9, 2024

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

@TimoSchmechel
Copy link

I think it might be similar to this: #8860
i came across that from #9092 when i was having similar issues with record types and private fields. i think you can force it to behave by adding the SDK reference

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants