Blazor supports DisplayName for models#17
Conversation
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Javier Calvarro Nelson <jacalvar@microsoft.com>
There was a problem hiding this comment.
Pull request overview
This pull request adds a new DisplayName component to Blazor that automatically renders display names for model properties by reading from DisplayAttribute, DisplayNameAttribute, or falling back to the property name. The PR updates project templates to use this component for form labels and includes comprehensive test coverage.
Changes:
- Introduces new
DisplayName<TValue>component for automatic label rendering - Adds
ExpressionMemberAccessorutility class to extract display names from model properties - Updates project templates (Login, Register, ResetPassword, etc.) to use
DisplayNamecomponent instead of hardcoded labels - Includes unit tests, E2E tests, and localization support
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Components/Web/src/Forms/DisplayName.cs | New component that renders display names for model properties |
| src/Components/Web/src/Forms/ExpressionMemberAccessor.cs | Utility class for extracting member metadata and display names from expressions |
| src/Components/Web/test/Forms/DisplayNameTest.cs | Comprehensive unit tests for DisplayName component |
| src/Components/test/E2ETest/Tests/FormsTest.cs | E2E test for DisplayName component behavior |
| src/Components/test/testassets/BasicTestApp/FormsTest/DisplayNameComponent.razor | Test component demonstrating various DisplayName usage patterns |
| src/Components/test/testassets/BasicTestApp/TestResources.cs | Wrapper for resource localization testing |
| src/Components/test/testassets/BasicTestApp/Resources.resx | Resource file with test data for localization |
| src/Components/test/testassets/BasicTestApp/Resources.fr.resx | French resource file for localization testing |
| src/Components/test/testassets/BasicTestApp/Index.razor | Added DisplayName component to test component list |
| src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/Account/Pages/ResetPassword.razor | Updated to use DisplayName component for form labels |
| src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/Account/Pages/Register.razor | Updated to use DisplayName component for form labels |
| src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/Account/Pages/Manage/Email.razor | Updated to use DisplayName component for form labels |
| src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/Account/Pages/Manage/ChangePassword.razor | Updated to use DisplayName component for form labels |
| src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/Account/Pages/Login.razor | Updated to use DisplayName component for form labels |
| src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWeb-CSharp/BlazorWebCSharp.1/Components/Account/Pages/ForgotPassword.razor | Updated to use DisplayName component for form labels |
| src/Components/Web/src/PublicAPI.Unshipped.txt | Added public API surface for DisplayName component |
| internal static class ExpressionMemberAccessor | ||
| { | ||
| private static readonly ConcurrentDictionary<Expression, MemberInfo> _memberInfoCache = new(); | ||
| private static readonly ConcurrentDictionary<MemberInfo, string> _displayNameCache = new(); |
There was a problem hiding this comment.
The _displayNameCache field is declared but never used in the code. Consider removing it if it's not needed, or implement caching for display names in the GetDisplayName method to improve performance.
| <InputText type="password" @bind-Value="Input.Password" id="Input.Password" class="form-control" autocomplete="current-password" aria-required="true" placeholder="password" /> | ||
| <label for="Input.Password" class="form-label"> | ||
| <DisplayName For="() => Input.Password" /> | ||
| </label> | ||
| <ValidationMessage For="() => Input.Password" class="text-danger" /> |
There was a problem hiding this comment.
The InputText element has inconsistent indentation. It should be indented to align with other elements in the same div block (should have 4 more spaces at the beginning).
| <InputText type="password" @bind-Value="Input.Password" id="Input.Password" class="form-control" autocomplete="current-password" aria-required="true" placeholder="password" /> | |
| <label for="Input.Password" class="form-label"> | |
| <DisplayName For="() => Input.Password" /> | |
| </label> | |
| <ValidationMessage For="() => Input.Password" class="text-danger" /> | |
| <InputText type="password" @bind-Value="Input.Password" id="Input.Password" class="form-control" autocomplete="current-password" aria-required="true" placeholder="password" /> | |
| <label for="Input.Password" class="form-label"> | |
| <DisplayName For="() => Input.Password" /> | |
| </label> | |
| <ValidationMessage For="() => Input.Password" class="text-danger" /> |
|
|
||
| private static void ClearCache() | ||
| { | ||
| _memberInfoCache.Clear(); |
There was a problem hiding this comment.
The ClearCache method clears _memberInfoCache but does not clear _displayNameCache. If _displayNameCache is intended to be used in the future, it should also be cleared here to maintain consistency during hot reload scenarios.
| _memberInfoCache.Clear(); | |
| _memberInfoCache.Clear(); | |
| _displayNameCache.Clear(); |
| <label for="Input.Email"> | ||
| <DisplayName For="() => Input.Email" /> | ||
| </label> | ||
| <ValidationMessage For="() => Input.Email" class="text-danger" /> | ||
| </div> | ||
| <div class="form-floating mb-3"> | ||
| <InputText type="password" @bind-Value="Input.Password" id="Input.Password" class="form-control" autocomplete="new-password" aria-required="true" placeholder="password" /> | ||
| <label for="Input.Password">Password</label> | ||
| <label for="Input.Password"> | ||
| <DisplayName For="() => Input.Password" /> | ||
| </label> |
There was a problem hiding this comment.
The label elements are inconsistent with the form-label CSS class. Labels on lines 32 and 39 are missing class="form-label" while the label on line 46 has it. For consistency across the form and with other similar pages (ResetPassword, Login, etc.), all labels should have class="form-label".
Benchmark PR from qodo-benchmark#84