Skip to content

Fully configure Identity for MVC and Razor Pages - #3834

Draft
danroth27 wants to merge 9 commits into
mainfrom
fix/3831-blazor-identity
Draft

danroth27 wants to merge 9 commits into
mainfrom
fix/3831-blazor-identity

Conversation

@danroth27

@danroth27 danroth27 commented Sep 18, 2026 •

Copy link
Copy Markdown
Member

Summary

Fully configure local Identity for MVC and Razor Pages, preserve existing configuration, and make repeated scaffolding a source-file no-op.

  • Add missing Razor Pages services, EF migration diagnostics, and Identity page mapping.
  • Inspect Identity registrations with Roslyn and complete missing UI, stores, token providers, and cookies without replacing existing registrations or options.
  • Preserve existing Identity user types and login partials. Generate the login partial through the existing T4 pipeline and integrate it into the host navbar without targeting unrelated or commented-out lists.
  • Generate an initial migration without applying it. Use evaluated MSBuild project metadata for the assets file and match migration snapshots to the exact context.
  • Resolve relative project paths, write Identity pages beneath the actual project directory, and create appsettings.json when it is missing.
  • Align the regular Identity templates for .NET 11 with the framework's default UI, including the correct typed no-op email-sender detection.

Fixes #3831

Cleanup and scope

The builder extensions configure steps rather than inspect source files. Existing project-analysis, code-modification, and templating infrastructure is reused. Navigation editing is separate from file generation, and one login-partial template is shared across supported target frameworks.

The end-to-end suite shares project/process setup and uses the matching installed SDK for each target framework. It requires generated pages at their canonical paths, so passing requests cannot conceal incorrectly placed pages by falling back to the packaged UI.

.NET 8 retains a separate host-modification configuration because WithStaticAssets() is unavailable there. No Blazor Identity templates are changed; the new user-type and migration analysis is gated to regular Identity.

.NET 11 Identity UI comparison

The template baseline remains dotnet/aspnetcore@13909f3b. Differences are limited to scaffolded application types/namespaces, host layout integration, and detecting the framework's internal typed email adapter through its type name and public legacy sender.

Validation

  • 300 regular Identity and connection-string regression tests passed, with no failures or skips.
  • All 15 integration/end-to-end scenarios passed across the final matrix and focused reruns: four clean MVC/Razor Pages cases on .NET 10/11, four existing-Identity cases, four partial-registration/custom-user cases, relative project paths, custom artifacts output, and the .NET 11 CLI integration test.
  • Lifecycle coverage exercises generated pages, static assets, registration, confirmation, login, authenticated Profile navigation, and logout.
  • Second scaffolding passes compare hashes of project files, excluding build artifacts, and make no changes. Initial migrations are generated without creating or modifying a database.
  • Both .NET 10 and .NET 11 tool builds passed. The shared login-partial template is packaged for all four supported target frameworks.

Add missing Identity services, authentication middleware, Razor Pages endpoints, login navigation, and an initial EF Core migration.

Add end-to-end coverage for clean MVC and Razor Pages projects, runtime endpoints, and repeated scaffolding.

Fixes #3831

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c90ed2f5-6b56-45f7-8157-d3fa618a7ffc
Verify that a second scaffolding pass leaves MVC and Razor Pages projects created with the default Identity UI unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c90ed2f5-6b56-45f7-8157-d3fa618a7ffc
Update the regular Identity scaffolder output to match the default Identity UI behavior and markup in dotnet/aspnetcore release/11.0.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c90ed2f5-6b56-45f7-8157-d3fa618a7ffc
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c90ed2f5-6b56-45f7-8157-d3fa618a7ffc
Apply the generated migration and verify registration, email confirmation, login, account management, logout, and Identity static assets.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c90ed2f5-6b56-45f7-8157-d3fa618a7ffc

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Four moderate issues remain in Identity registration detection, navbar insertion, layout integration, and external-login navigation.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Configures ASP.NET Core Identity for MVC and Razor Pages, adds migration and navigation support, updates .NET 11 templates, and expands integration coverage.

Changes:

  • Adds Identity host configuration, navigation, and EF migration generation.
  • Aligns .NET 11 Identity templates with the default UI.
  • Expands unit, integration, and end-to-end tests.
File summaries
File Summary
test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/ScaffoldSteps/ConfigureIdentityNavigationStepTests.cs Navigation tests
test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/ScaffoldSteps/AddIdentityMigrationStepTests.cs Migration tests
test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/Identity/IdentityNet11IntegrationTests.cs .NET 11 integration tests
test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/Identity/IdentityIntegrationTestsBase.cs Identity test infrastructure
test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Integration/Identity/IdentityEndToEndNet10Tests.cs End-to-end lifecycle tests
test/dotnet-scaffolding/dotnet-scaffold.Tests/AspNet/Extensions/IdentityScaffolderBuilderExtensionsTests.cs Builder extension tests
src/dotnet-scaffolding/dotnet-scaffold/dotnet-scaffold.csproj Packaging updates
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net8.0/CodeModificationConfigs/identityChanges.json .NET 8 Identity configuration
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/ResetPasswordModel.tt Reset password template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/ResetPasswordModel.cs Reset password output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/ResendEmailConfirmationModel.tt Resend confirmation template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/ResendEmailConfirmationModel.cs Resend confirmation output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/RegisterModel.tt Registration model template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/RegisterModel.cs Registration model output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/RegisterConfirmationModel.tt Registration confirmation template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/RegisterConfirmationModel.cs Registration confirmation output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Register.tt Registration page template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Register.cs Registration page output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/SetPassword.tt Set-password template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/SetPassword.cs Set-password output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/PersonalData.tt Personal-data template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/PersonalData.cs Personal-data output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/ManageNavPagesModel.tt Manage navigation model template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/ManageNavPagesModel.cs Manage navigation model output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/Index.tt Manage index template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/Index.cs Manage index output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/ExternalLogins.tt External logins template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/ExternalLogins.cs External logins output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/EnableAuthenticator.tt Authenticator template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/EnableAuthenticator.cs Authenticator output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/EmailModel.tt Email model template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/EmailModel.cs Email model output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/Email.tt Email page template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/Email.cs Email page output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/ChangePassword.tt Password-change template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/ChangePassword.cs Password-change output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/_ManageNav.tt Manage navigation template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/_ManageNav.cs Manage navigation output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/_Layout.tt Manage layout template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/_Layout.cs Manage layout output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/LogoutModel.tt Logout model template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/LogoutModel.cs Logout model output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/LoginWithRecoveryCodeModel.tt Recovery-code template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/LoginWithRecoveryCodeModel.cs Recovery-code output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/LoginWith2faModel.tt Two-factor model template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/LoginWith2faModel.cs Two-factor model output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/LoginModel.tt Login model template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/LoginModel.cs Login model output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Login.tt Login page template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Login.cs Login page output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/ForgotPasswordModel.tt Password-recovery template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/ForgotPasswordModel.cs Password-recovery output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/ExternalLoginModel.tt External-login template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/ExternalLoginModel.cs External-login output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/ConfirmEmailModel.tt Email-confirmation template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/ConfirmEmailModel.cs Email-confirmation output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/ConfirmEmailChangeModel.tt Email-change template
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/ConfirmEmailChangeModel.cs Email-change output
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/CodeModificationConfigs/identityChanges.json .NET 11 Identity configuration
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net10.0/CodeModificationConfigs/identityChanges.json .NET 10 Identity configuration
src/dotnet-scaffolding/dotnet-scaffold/AspNet/ScaffoldSteps/ConfigureIdentityNavigationStep.cs Navigation integration
src/dotnet-scaffolding/dotnet-scaffold/AspNet/ScaffoldSteps/AddIdentityMigrationStep.cs Migration generation
src/dotnet-scaffolding/dotnet-scaffold/AspNet/Extensions/IdentityScaffolderBuilderExtensions.cs Identity pipeline registration
src/dotnet-scaffolding/dotnet-scaffold/AspNet/AspNetCommandService.cs Scaffold pipeline integration
Review details

Suppressed comments (3)

src/dotnet-scaffolding/dotnet-scaffold/AspNet/Extensions/IdentityScaffolderBuilderExtensions.cs:178

  • This only recognizes registrations written with the literal builder.Services.Add... prefix. A valid existing setup such as var services = builder.Services; services.AddIdentity<...>() (or a line-broken/aliased AddDefaultIdentity) is treated as absent, so the code-modification step inserts a second Identity registration. That violates the no-duplicate/preserve-customization requirement; detect the registration structurally (or use the same code-analysis mechanism as the modifier) rather than relying on this exact text.
            if (programContent.Contains(registration, StringComparison.Ordinal))

src/dotnet-scaffolding/dotnet-scaffold/AspNet/ScaffoldSteps/ConfigureIdentityNavigationStep.cs:42

  • When _LoginPartial.cshtml already exists but is not referenced by this layout (for example, a project-owned partial in Shared), this early return prevents adding the layout reference, so the generated Login/Register links are never reachable. The existing partial should be preserved, but layout configuration must continue unless the layout already references it.
        if (layoutContent.Contains("_LoginPartial", StringComparison.OrdinalIgnoreCase))
        {
            return Task.FromResult(true);

src/dotnet-scaffolding/dotnet-scaffold/AspNet/Templates/net11.0/Identity/Pages/Account/Manage/_ManageNav.tt:11

  • _ManageNav now tests ViewData["ManageNav.HasExternalLogins"], but none of the generated Identity templates set that key (the previous implementation computed hasExternalLogins from SignInManager). As a result, applications with configured external providers will silently omit the External logins management link. Either restore the local SignInManager query or add the corresponding ViewData initialization to the manage layout/pages before rendering this partial.
  • Files reviewed: 64/65 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +49 to +51
var closingListIndex = openingListIndex < 0
? -1
: layoutContent.IndexOf("</ul>", navbarClassIndex, StringComparison.OrdinalIgnoreCase);
danroth27 and others added 4 commits September 18, 2026 13:56
Apply the generated migration through an isolated runner project so CI output path settings do not break dotnet-ef on macOS.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c90ed2f5-6b56-45f7-8157-d3fa618a7ffc
Exercise the generated migrations endpoint so the lifecycle test avoids platform-specific dotnet-ef output paths and secondary Razor builds.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c90ed2f5-6b56-45f7-8157-d3fa618a7ffc
Find the closing ul that matches the navbar list before inserting the Identity login partial, with regression coverage for nested dropdown lists.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c90ed2f5-6b56-45f7-8157-d3fa618a7ffc
Reuse Roslyn and MSBuild project analysis, preserve existing Identity configuration, and generate host navigation through the template pipeline. Fix project-relative output paths, missing appsettings creation, and .NET 11 no-op email-sender detection.

Consolidate SDK-pinned MVC and Razor Pages lifecycle coverage, require canonical generated pages, and verify unchanged second scaffolding runs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7f8f84a2-809d-43db-b74e-4f4f888dfd4c
@danroth27
danroth27 marked this pull request as draft September 23, 2026 02:03
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

Successfully merging this pull request may close these issues.

Make the Identity scaffolder fully configure MVC and Razor Pages projects

2 participants