diff --git a/Analysis-of-AspNetCoreFeatures.Toggles-by-GitHub-Copilot.md b/Analysis-of-AspNetCoreFeatures.Toggles-by-GitHub-Copilot.md new file mode 100644 index 0000000..9ee2003 --- /dev/null +++ b/Analysis-of-AspNetCoreFeatures.Toggles-by-GitHub-Copilot.md @@ -0,0 +1,160 @@ +## :bust_in_silhouette: (8/29/2026 7:18 AM) +Analyze this solution, tell me what it does, what it uses, and how it does it. +## :speech_balloon: GitHub Copilot +1. Read AspNetCoreFeatures.Toggles.sln, lines 1-300 :white_check_mark: + +1. Read README.md, lines 1-260 :white_check_mark: +1. Read AspNetCoreFeatures.Toggles.Server.csproj, lines 1-220 :white_check_mark: +1. Read AspNetCoreFeatures.Toggles.Client.csproj, lines 1-220 :white_check_mark: +1. Read AspNetCoreFeatures.Toggles.Shared.csproj, lines 1-220 :white_check_mark: + +1. Read Program.cs, lines 1-320 :white_check_mark: +1. Read Program.cs, lines 1-260 :white_check_mark: +1. Read appsettings.json, lines 1-260 :white_check_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Server\appsettings.Development.json'. :negative_squared_cross_mark: + +1. Read FeatureXService.cs, lines 1-220 :white_check_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Server\Controllers\FeatureXController.cs'. :negative_squared_cross_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Server\Controllers\WeatherForecastController.cs'. :negative_squared_cross_mark: +1. Read Index.razor, lines 1-260 :white_check_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Client\Pages\FeatureXPage.razor'. :negative_squared_cross_mark: +1. Read App.razor, lines 1-260 :white_check_mark: + +1. Read NavMenu.razor, lines 1-320 :white_check_mark: +1. Read MainLayout.razor, lines 1-220 :white_check_mark: +1. Read _Host.cshtml, lines 1-320 :white_check_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Server\Controllers\WeatherForecastController.cs'. :negative_squared_cross_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Server\Controllers\FeatureManagementController.cs'. :negative_squared_cross_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Server\Controllers\DataEventRecordsController.cs'. :negative_squared_cross_mark: + +1. Read DirectApi.razor, lines 1-320 :white_check_mark: +1. Read FeatureXApi.razor, lines 1-320 :white_check_mark: +1. Read GraphApiCall.razor, lines 1-320 :white_check_mark: +1. Read AccountController.cs, lines 1-320 :white_check_mark: +1. Read DirectApiController.cs, lines 1-320 :white_check_mark: +1. Read FeatureXApiController.cs, lines 1-320 :white_check_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Server\Controllers\GraphApiCallController.cs'. :negative_squared_cross_mark: + +1. Read GraphApiCallsController.cs, lines 1-320 :white_check_mark: +1. Read MsGraphService.cs, lines 1-360 :white_check_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Server\Services\CaeClaimsChallengeService.cs'. :negative_squared_cross_mark: +1. Read SecurityHeadersDefinitions.cs, lines 1-360 :white_check_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Server\UseNoUnauthorizedRedirectExtensions.cs'. :negative_squared_cross_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Server\NotFoundMapExtensions.cs'. :negative_squared_cross_mark: +1. Read Features.cs, lines 1-120 :white_check_mark: +1. Read AntiforgeryHttpClientFactory.cs, lines 1-320 :white_check_mark: +1. Read AuthorizedHandler.cs, lines 1-260 :white_check_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Client\HostAuthenticationStateProvider.cs'. :negative_squared_cross_mark: +1. Found 1 results for symbol HostAuthenticationStateProvider :white_check_mark: + +1. Read HostAuthenticationStateProvider.cs, lines 1-360 :white_check_mark: +1. Read IAntiforgeryHttpClientFactory.cs, lines 1-120 :white_check_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Server\wwwroot\antiForgeryToken.js'. :negative_squared_cross_mark: +1. Read UserController.cs, lines 1-260 :white_check_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Shared\UserInfo.cs'. :negative_squared_cross_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Server\Controllers\ProfileController.cs'. :negative_squared_cross_mark: + +1. Found 1 results for symbol UseNoUnauthorizedRedirect :white_check_mark: +1. Found 1 results for symbol MapNotFound :white_check_mark: +1. Found 1 results for symbol CaeClaimsChallengeService :white_check_mark: +1. Read antiForgeryToken.js, lines 1-120 :white_check_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Server\wwwroot\js\antiForgeryToken.js'. :negative_squared_cross_mark: +1. Read UserInfo.cs, lines 1-260 :white_check_mark: +1. Read ClaimValue.cs, lines 1-220 :white_check_mark: + +1. Read ApplicationBuilderExtensions.cs, lines 1-220 :white_check_mark: +1. Read EndpointRouteBuilderExtensions.cs, lines 1-220 :white_check_mark: +1. Read CaeClaimsChallengeService.cs, lines 1-320 :white_check_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Server\Cae\CaeUnauthorizedResultFilter.cs'. :negative_squared_cross_mark: +1. Read GraphApiCallsController.cs, lines 1-320 :white_check_mark: +1. No results found for symbol CheckForRequiredAuthContextIdToken :white_check_mark: +1. Found 3 results for symbol FEATUREX :white_check_mark: +1. Found 1 results for symbol CaeClaimsChallengeService :white_check_mark: +1. No results found for symbol GetGraphApiProfilePhoto :white_check_mark: + +1. Read _Imports.razor, lines 1-220 :white_check_mark: +1. Read appsettings.json, lines 1-220 :white_check_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Client\wwwroot\appsettings.Development.json'. :negative_squared_cross_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Server\Pages\_Layout.cshtml'. :negative_squared_cross_mark: +1. Read Error.cshtml, lines 1-220 :white_check_mark: +1. Couldn't run get_tests :negative_squared_cross_mark: +1. No tests found matching filters: Outcome=None :white_check_mark: +1. Read dotnet.yml, lines 1-260 :white_check_mark: + +1. Read launchSettings.json, lines 1-260 :white_check_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Client\Properties\launchSettings.json'. :negative_squared_cross_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Server\Pages\_ViewImports.cshtml'. :negative_squared_cross_mark: +1. Couldn't find file 'D:\GitHub\AspNetCoreFeatures.Toggles\Server\Pages\_ViewStart.cshtml'. :negative_squared_cross_mark: +1. Read Error.cshtml.cs, lines 1-200 :white_check_mark: +1. No results found for symbol AntiForgeryTokenInput :white_check_mark: +1. Read AntiForgeryTokenInput.razor, lines 1-120 :white_check_mark: +### Solution Summary + +This is a **hosted Blazor WebAssembly app** on **.NET 10** that demonstrates **feature toggles** with authenticated API access. + +It has 3 projects: + +- `Server` (`Microsoft.NET.Sdk.Web`) +- `Client` (`Microsoft.NET.Sdk.BlazorWebAssembly`) +- `Shared` (shared DTO/constants) + +--- + +### What it does + +- Uses **Microsoft Entra ID / Azure AD** sign-in with **cookie auth**. +- Exposes secured server APIs: + - `api/DirectApi` + - `api/FeatureXApi` + - `api/GraphApiCalls` + - auth endpoints in `api/Account/*` + - current user endpoint `api/User` +- Shows/hides functionality via a feature flag (`FeatureX`): + - menu item visibility in `Client/Shared/NavMenu.razor` + - page behavior in `Client/Pages/FeatureXApi.razor` + - API behavior in `Server/Controllers/FeatureXApiController.cs` +- Calls Microsoft Graph (`Me`) and returns profile fields. +- Applies strict security defaults (CSP, HSTS, anti-forgery, removed server header). + +--- + +### What it uses + +- **Feature flags** + - `Microsoft.FeatureManagement` (client) + - `Microsoft.FeatureManagement.AspNetCore` (server) + - Feature key constant in `Shared/Features.cs` + - Configured in both: + - `Server/appsettings.json` + - `Client/wwwroot/appsettings.json` +- **Identity and Graph** + - `Microsoft.Identity.Web` + - `Microsoft.Identity.Web.UI` + - `Microsoft.Identity.Web.GraphServiceClient` +- **Security** + - `NetEscapades.AspNetCore.SecurityHeaders` + - Anti-forgery token flow with JS helper `Client/wwwroot/antiForgeryToken.js` +- **Image processing** + - `Magick.NET-Q16-AnyCPU` (used in `MsGraphService.GetGraphApiProfilePhoto`, currently not wired to a controller route) + +--- + +### How it works (request flow) + +1. App boots from Razor Page host `Server/Pages/_Host.cshtml` and loads Blazor WASM. +2. `Client/Services/HostAuthenticationStateProvider.cs` fetches `api/User` to determine auth state. +3. If unauthorized, client redirects to `api/Account/Login`. +4. For secured API calls, client adds anti-forgery header (`X-XSRF-TOKEN`) via `AntiforgeryHttpClientFactory`. +5. Server validates anti-forgery and cookie auth on API controllers. +6. Feature X is checked with `IFeatureManager` on both client and server. +7. Graph endpoint uses delegated scopes and `GraphServiceClient`. + +--- + +### Notable implementation details + +- `FeatureXService` is only registered when `FeatureManagement:FeatureX` is `true` in server config (`Program.cs`). +- `UseNoUnauthorizedRedirect("/api")` marks API calls as AJAX to avoid redirect-style auth behavior. +- `MapNotFound("/api/{**segment}")` forces unmapped API routes to return HTTP 404. +- CI workflow (`.github/workflows/dotnet.yml`) restores/builds/tests on .NET 10. +- No test cases are currently discovered in Test Explorer (`Outcome=None` returned no tests).