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

Add validation for MetadataType attribute - Issue #46678 #51772

Merged
2 commits merged into from
Jul 28, 2021
Merged

Add validation for MetadataType attribute - Issue #46678 #51772

2 commits merged into from
Jul 28, 2021

Conversation

Xaeco
Copy link
Contributor

@Xaeco Xaeco commented Apr 24, 2021

If a MetadataType attribute is applied to a class the associated metadata class is now validated in .NET Core.

In .NET Framework 4.8 and older versions a similar behavior already exists if you use associate a type and handler like so:
TypeDescriptor.AddProviderTransparent( new AssociatedMetadataTypeTypeDescriptionProvider(typeof(Person), typeof(PersonMetadata)), typeof(Person));

To do this the System.ComponentModel.DataAnnotations.ValidationAttributeStore class was altered to check for a MetadataType attribute. If found it inspects the associated class and merges any validation attributes with any from the class being validated.

Added tests to the System.ComponentModel.DataAnnotations.Validator for as many scenarios as I could think of.

Fixes #46678

@ghost
Copy link

ghost commented Apr 24, 2021

Tagging subscribers to this area: @ajcvickers
See info in area-owners.md if you want to be subscribed.

Issue Details

Fix for #46678

If MetadataType attribute is applied to a class the associated metadata class is now validated.

To do this the System.ComponentModel.DataAnnotations.ValidationAttributeStore class was altered to check for a MetadataType attribute and add the properties from associated class to the store.

Added tests to the System.ComponentModel.DataAnnotations.Validator for as many scenarios as I could think of.

Author: Xaeco
Assignees: -
Labels:

area-System.ComponentModel.DataAnnotations

Milestone: -

@dnfadmin
Copy link

dnfadmin commented Apr 24, 2021

CLA assistant check
All CLA requirements met.

@Xaeco
Copy link
Contributor Author

Xaeco commented May 8, 2021

@ajcvickers what is the process and timeline to get someone to review my PR? Also I can't get this to build due to the Helix failures that keep happening. Seems to be a common issue.

Tagging in @lajones

@Xaeco
Copy link
Contributor Author

Xaeco commented May 28, 2021

@ajcvickers @eerhardt @lajones when's the next time this can be reviewed ?
Thanks

Comment on lines 247 to 252
var properties = t.GetProperties()
.Where(prop => !prop.GetIndexParameters().Any());

foreach (PropertyInfo property in properties)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var properties = t.GetProperties()
.Where(prop => !prop.GetIndexParameters().Any());
foreach (PropertyInfo property in properties)
{
foreach (PropertyInfo property in t.GetProperties())
{
if (property.GetIndexParameters().Length == 0)
{

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should you also be filtering static properties? GetProperties() returns both instance and static properties.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've incorporated your suggested code. Is the reasoning of the style change to reduce memory and object iteration for performance reasons?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eerhardt Re static properties: Only public static properties will be processed. This is the same behavior as in .Net Framework. My branch finally got through all the pipelines, yay, progress. Thanks for all your help.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the reasoning of the style change to reduce memory and object iteration for performance reasons?

Yes. In general, we have been moving away from using Linq in the BCL. See #44923 #44825 #47496 #47873 #44734

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eerhardt Kewl. No pressure but what's the usual turnaround for PR reviews like this one? Just setting my expectations 😎

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would hope the area owners would review this change. I'm just here reviewing because I was pinged on the issue, and was helping out on the "trim compatibility" parts of it.

@ajcvickers

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Would it be appropriate for you to assign the review to ajcvickers?

@Xaeco Xaeco requested a review from eerhardt May 29, 2021 08:45
@Xaeco
Copy link
Contributor Author

Xaeco commented Jun 16, 2021

@ajcvickers can we progress this? I and others have a lot of work with this as a dependency.

@Xaeco
Copy link
Contributor Author

Xaeco commented Jun 25, 2021

Hi @eerhardt. Trying to progress this before .Net 6 is released 😂. I was wondering if this PR is setup/tagged correctly for the associated bug? Also any other settings, or advice to progress this would be appreciated. Thanks

@ajcvickers
Copy link
Contributor

Sorry for being so slow on this. We are normally very hesitant to take changes in this area, especially where the behavior in .NET Framework and .NET Core would diverge. However, in this case we are bringing an existing .NET Framework behavior to .NET Core, which actually helps convergence.

@bricelam I think you have some knowledge in this area. Does the change make sense to you?
@roji Another set of eyes would be good.

Copy link
Member

@roji roji left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As @ajcvickers wrote, apologies for being so slow on this (I've been on vacation in the last three weeks).

I'm unfamiliar with this area, but the main question that comes to mind, is whether we shouldn't simply match the .NET Framework behavior here - more or less by copying the code across - rather than adding the new feature here (as @ajcvickers wrote this area is archived to a large extent). If I understand the situation correctly, this would mean that [MetadataType] wouldn't be respected for validation (it wasn't for .NET Framework), but TypeDescriptor.AddProviderTransparent would.

In any case, deferring to @bricelam (and @ajcvickers) who know this better.

@bricelam
Copy link
Contributor

+1 for using the .NET Framework code as reference. When all this code came into .NET Core, MetadataTypeAttribute was deliberately excluded (no idea why), and it was later brought in as part of the push to make .NET Framework apps compatible with .NET Core.

@bricelam bricelam self-assigned this Jul 12, 2021
@Xaeco
Copy link
Contributor Author

Xaeco commented Jul 16, 2021

@bricelam . So I'm wondering what the next steps are. I'd like to keep this moving.

Appreciate everyone's feedback, thanks.

@roji
Copy link
Member

roji commented Jul 16, 2021

See #51772 (comment)

@terrajobst terrajobst added the community-contribution Indicates that the PR has been added by a community member label Jul 19, 2021
/// </remarks>
/// <param name="propertyDescriptor">The property descriptor whose attributes are needed.</param>
/// <returns>A new <see cref="AttributeCollection"/> stripped of any attributes from the property's type.</returns>
public static AttributeCollection GetExplicitAttributes(PropertyDescriptor propertyDescriptor)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this method public? It seems to only be used by this class.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 that would be a copy & paste fail from .NET Framework. Changed to internal. Thanks

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nit) Does it even need to be internal? Why not private?

@Xaeco Xaeco requested review from vitek-karas and roji July 21, 2021 10:15
@karelz
Copy link
Member

karelz commented Jul 21, 2021

Http3_MsQuic test failures are tracked in #56090. Should be fixed and merged shortly. Sorry for the inconvenience!

@Xaeco Xaeco requested a review from eerhardt July 22, 2021 06:44
@eerhardt
Copy link
Member

This looks good to me. Thanks @Xaeco for the contribution here.

@roji @bricelam - any more feedback?

@Xaeco
Copy link
Contributor Author

Xaeco commented Jul 22, 2021

Awesome it's approved! 😀. Thanks everyone. This is my first GitHub PR. Does it get auto-completed & merged or do I need to do something?

@ajcvickers
Copy link
Contributor

@bricelam Can you take a final look at this when you get in today?

@danmoseley @Pilchie Does this need to go through Ask Mode to get in for .NET 6?

@danmoseley
Copy link
Member

@ajcvickers there are no permissions (ever?) needed to fix anything in dotnet/runtime main. However on Aug 17 it will become a 7.0 branch so there would be ceremony if it wasn't in by then.

@bricelam
Copy link
Contributor

bricelam commented Jul 26, 2021

@Xaeco It looks like GetTypeStoreItem should also use TypeDescriptor to pick up type-level attributes on the buddy type. Wanna make the update and add some tests for this scenario?

@bricelam
Copy link
Contributor

Updated to honor class-level attributes. Squashed and rebased on top of main.

@ghost
Copy link

ghost commented Jul 27, 2021

Hello @bricelam!

Because this pull request has the auto-merge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

@bricelam
Copy link
Contributor

Looks like scenarios involving dynamically added properties will also be enabled by this PR.

@Xaeco
Copy link
Contributor Author

Xaeco commented Jul 27, 2021

@Xaeco It looks like GetTypeStoreItem should also use TypeDescriptor to pick up type-level attributes on the buddy type. Wanna make the update and add some tests for this scenario?

@bricelam thanks for making those changes. I started to but got interrupted and should've mentioned I was working on it.

@ghost ghost merged commit 5d42771 into dotnet:main Jul 28, 2021
@IanKemp
Copy link

IanKemp commented Jul 28, 2021

Thanks guys!

@bricelam
Copy link
Contributor

And thank you, community, for making it happen! Things like this that bring parity with .NET Framework make everyone's migration go a little smoother.

@Gambero81
Copy link

Gambero81 commented Jul 29, 2021

Glad to find this issue merged in .net6, can be ported to .net5?

@roji
Copy link
Member

roji commented Jul 29, 2021

@Gambero81 this is very unlikely to be backported to .NET 5.0; patches are only done for serious bugs for which no workaround is available.

This pull request was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.ComponentModel.DataAnnotations community-contribution Indicates that the PR has been added by a community member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

MetadataTypeAttribute doesn't influence DataAnnotations validation result