-
Notifications
You must be signed in to change notification settings - Fork 23
Update version to 2.0.0 and target ODL 8 and .NET 8.0 #41
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
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Member
|
why don't update the version to 2.0.0? and target to .NET 8 also? |
Contributor
Author
|
@xuzhg that's an option we can pursue, I didn't want to make a major breaking change unless it was necessary to support ODL 8. In the case of ModelBuilder, it's not necessary. But I can go ahead and make that change since .NET 6.0 is going out of support soon. |
ElizabethOkerio
approved these changes
Aug 16, 2024
WanjohiSammy
approved these changes
Aug 16, 2024
Contributor
Author
Contributor
Author
|
The nightly pipeline needs to be fixed. Pipelines should also be ported to 1ES. |
xuzhg
approved these changes
Aug 16, 2024
d88ffbd to
a7d09f2
Compare
a7d09f2 to
8b5c9d4
Compare
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Issues
The version constraint excludes ODL 8.
This causes the following warning when you install
Microsoft.OData.ModelBuilderalongsideMicrosoft.OData.Edm8.0.0.Description
The PR changes the target framework to .NET 8 and ODL version to ODL 8.0.0.
It also made the following changes:
nullinstead of 0. The default scale value was actually changed to null in ODL 7.11.0. But ModelBuilder was still targeting ODL 7.9.0, so this issue was never caught.EntityType()extension method with theEntityTypepropertyGetCustomAttributesthat was introduced in .NET 7. This is a bit involved, so I'll explain that in detail below.Notes on property attribute mocking and failing tests
After I changed the target framework to .NET 8.0.0, 24 tests failed with an

InvalidCastExceptionerror:The exception was thrown from this statement in .NET
This codepath is reached when we call a method like
propertyInfo.GetCustomAttribute<SomeAttributeType>()orpropertyInfo.GetCustomAttributes<SomeAttributeType>().And we're doing that a couple of places, like on
ODataConventionModelBuilderclass where we check presence of theContainedAttributeto determine whether a navigation property is contained.Why was the
InvalidCastExceptionbeing thrown?The exception was being thrown because it so happens that the
element.GetCustomAttributes(attributeType, inherit)was return an empty array of typeobject[]. And .NET was trying to cast that toAttribute[]. This cast fails and throws the exception.Why was the exception not thrown before changing the target to .NET 8.0.0?
Previously, our target frameworks were .NET standard 2.0 and .NET 6.0. Prior to .NET 7, the custom attribute code used to look like this
Since this uses the
askeyword is used for the cast, it returnsnullinstead of throwing an exception when the cast fails.2 years ago (i.e. .NET 7), this PR changed the implementation to:
which throws an exception if the cast fails.
Why did
element.GetCustomAttributes(attributeType, inherit)return anobject[]array instead ofAttribute[]array?It so happens that in the tests that fail, the property info was not an actual
PropertyInfo, but a mock. We use helper methods in [MockType.cs]((https://github.com/OData/ModelBuilder/blob/main/test/Microsoft.OData.ModelBuilder.Tests/Commons/MockType.cs) to mockTypeandPropertyInfoinstances for use in tests.The
MockType.Property()method adds a mock property info to a type and is supposed to mock the inheritedMemberInfo.GetCustomAttributes()method as well.It so happens this method has two overloads:
object[] GetCustomAttributes(bool inherit)which is supposed to return all attributes regardless of the attribute typeobject[] GetCustomAttributes(Type attributeType, bool inherit)which should return only attributes of the specified typeNote that the declared return type of these methods is
object[]. Despite the return type being so open, the excepted return type should beAttribute[]for the first overload and an array of the target attribute type for the other method.It also so happens that only the first overload was being mocked:
The second overload was not being mocked. If a method is not mocked, I think Moq (the mocking library we use) generates a mock method that returns a default instance of the declared return type, which in this case would be an empty array of type
object[](and notAttribute[]).Coincidentally, the
GetCustomAttribute<T>()andGetCustomAttributes<T>()extension methods called by ModelBuilder call the secondMemberInfo.GetCustomAttributes(Type attributeType, bool inherit)overload. Which in the case of this mock, returns an emptyobject[]array, which the implementation attempts to cast toAttribute[]resulting in theInvalidCastException.If the overload was no mocked, then how did tests that tested against custom attributes like
RequiredAttributepass without issues before?Yes, we do have some tests that verify that specific attributes are handled properly by the model builder, like this one
It so happens that some parts of model builder call
propertyInfo.GetCustomAttributes()and then perform a filter on the result (e.g.GetCustomAttributes().OfType<T>(), and other parts callproptertyInfo.GetCustomAttribute<T>(). Code that use the first variant was not affected because they used the overload that was already mocked.I also noticed that after introducing the fix, I didn't get failing tests that tested the
ContainedAttribute. Yet this was one of the code paths leading to the failing tests. I realized that existing tests that tested the ContainedAttribute did not use the mock approach, but used real types that had theContainedattribute applied to some properties. Since they did not use the mock, they were not affected by the breaking change.To make the sure the fix to the mocking logic works, I added a test that verifies the behaviour of the
Containedattribute using mocks.But my main take away is that we should avoid relying on mocks for types that are used in ways we do not control or that can be changed in ways we cannot predict.
Checklist (Uncheck if it is not completed)