Skip to content

Add generic variants of MVC attributes #47075

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
merged 3 commits into from
May 16, 2023
Merged

Add generic variants of MVC attributes #47075

merged 3 commits into from
May 16, 2023

Conversation

captainsafia
Copy link
Member

@captainsafia captainsafia commented Mar 7, 2023

Closes #37767.

Since we have derived classes, the behavior of GetCustomAttribute is now different. I've updated the impacted codepaths that I could find.

I didn't replace all instances of ServiceFilter and TypeFilter in our tests because some of them don't reference types that actually implement the IFilterMetadata interface (example). These tests aren't currently failing because they don't actually instantiate the factories.

@captainsafia captainsafia marked this pull request as ready for review March 7, 2023 20:28
@captainsafia captainsafia requested review from halter73, brunolins16 and a team as code owners March 7, 2023 20:28
Copy link
Member

@JamesNK JamesNK left a comment

Choose a reason for hiding this comment

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

The new attributes are basically the same, e.g. [ModelMetadataType(typeof(DerivedModel))] vs [ModelMetadataType<DerivedModel>] - but it would be good to still have tests that using typeof(XXX) works - realistically existing MVC code that uses the non-generic attributes will always be the majority of users. Are there still some left or have the tests all been updated to be generic?

I'd like a test of multiple attributes, e.g. [ModelMetadataType(typeof(DerivedModel))] and [ModelMetadataType<DerivedModel>], and verify the error message is descriptive.

@amcasey
Copy link
Member

amcasey commented Mar 8, 2023

LGTM, modulo @JamesNK's suggestions.

@captainsafia
Copy link
Member Author

The new attributes are basically the same, e.g. [ModelMetadataType(typeof(DerivedModel))] vs [ModelMetadataType] - but it would be good to still have tests that using typeof(XXX) works - realistically existing MVC code that uses the non-generic attributes will always be the majority of users. Are there still some left or have the tests all been updated to be generic?

Yes, there are integration tests that still use the existing model (https://github.com/dotnet/aspnetcore/blob/fd211fb22e07f8b03e72d64b50117ba5d4ddf9a4/src/Mvc/test/Mvc.IntegrationTests/Models/SoftwareViewModel.cs). Also, I think we have decent coverage for it given that we call into the base constructor.

I'd like a test of multiple attributes, e.g. [ModelMetadataType(typeof(DerivedModel))] and [ModelMetadataType], and verify the error message is descriptive.

Done. Thoughts?

@@ -287,6 +287,18 @@ public void GetAttributesForProperty_WithModelType_IncludesTypeAttributes()
attribute => Assert.IsType<ClassValidator>(attribute));
}

[Fact]
public void GetAttributeForProperty_WithModelType_HandlesMultipleAttributesOnType()
Copy link
Member

Choose a reason for hiding this comment

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

Great!

This covers ModelMetadataType. Are there other attributes that had AllowMultiple=false?

Copy link
Member Author

@captainsafia captainsafia Mar 14, 2023

Choose a reason for hiding this comment

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

ModelBinder has it, but it's behavior is a little interesting. When constructing the model-binding context, we capture all the attributes on a type, including inherited ones (ref). When constructing the actual model binding context, we pick the attribute closest to the type were evaluating and use its properties to construct the context (ref).

So unlike the ModelMetadata scenario, there isn't a place in code where we try to evaluate a single attribute on a type. We could modify the binding logic above to throw if there are multiple attributes on the same type. That would introduce a new exception in the code (although it's not possible to hit that exception without this current change).

Ditto the same situation for ProducesAttribute. Although we only expect one attribute on a particular type, all the codepaths that consume it assume that attributes can be inherited and don't strictly expect a single attribute to be defined.

So we can throw exceptions at runtime that warn about multiple attributes on the same type but that feels a little heavy handed given the existing behavior for these attributes.

Thoughts?

@ghost
Copy link

ghost commented Mar 21, 2023

Looks like this PR hasn't been active for some time and the codebase could have been changed in the meantime.
To make sure no breaking changes are introduced, please leave an /azp run comment here to rerun the CI pipeline and confirm success before merging the change.

@ghost ghost added the pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun label Mar 21, 2023
@captainsafia captainsafia force-pushed the safia/generic-attrs branch from 98673d4 to f5fdc0a Compare May 15, 2023 16:43
@captainsafia captainsafia added area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates and removed pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun labels May 15, 2023
@captainsafia
Copy link
Member Author

captainsafia commented May 15, 2023

Bump! Reviving this for preview5.

@captainsafia captainsafia merged commit 002260d into main May 16, 2023
@captainsafia captainsafia deleted the safia/generic-attrs branch May 16, 2023 15:21
@ghost ghost added this to the 8.0-preview5 milestone May 16, 2023
@marchy
Copy link

marchy commented May 25, 2023

Stoked! The typeof( .. ) was always such a clunky add-on that added noise to all our authorized routes.

Great work team!

@ghost
Copy link

ghost commented May 25, 2023

Hi @marchy. It looks like you just commented on a closed PR. The team will most probably miss it. If you'd like to bring something important up to their attention, consider filing a new issue and add enough details to build context.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add generic versions of attributes in ASP.NET Core
6 participants