Use source generator to bind configuration in bit Boilerplate (#12679)#12680
Conversation
WalkthroughThe boilerplate adds tenant custom-domain support across contracts, validation, persistence, resolution, UI, and localization. It also introduces dynamic configuration binding, refactors nullable database indexes, moves forwarded-header binding to configuration sections, and adds Playwright MCP tooling. ChangesTenant custom-domain support
Nullable uniqueness indexes
Runtime configuration updates
Playwright template tooling
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant TenantController
participant TenantStore
participant TenantProvider
Client->>TenantController: submit tenant domain
TenantController->>TenantStore: validate normalized domain uniqueness
TenantStore-->>TenantController: validation result
Client->>TenantProvider: request with host
TenantProvider->>TenantStore: read active tenant lookup
TenantStore-->>TenantProvider: domain and name mappings
TenantProvider-->>Client: resolved tenant context
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Infrastructure/Extensions/IConfigurationExtensions.cs (1)
15-18: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueCache the
MethodInfoto avoid repeated reflection overhead.Since
DynamicBindwill be executed during application startup and potentially upon every runtime configuration reload viaIOptionsMonitor, consider caching theMethodInfoin a static readonly field. This avoids the overhead of discovering the method via reflection on each invocation.♻️ Proposed refactor
+ private static readonly System.Reflection.MethodInfo? BindMethod = typeof(ConfigurationBinder).GetMethod(nameof(ConfigurationBinder.Bind), [typeof(IConfiguration), typeof(object)]); + public IConfiguration DynamicBind<T>(T options) { - typeof(ConfigurationBinder).GetMethod(nameof(ConfigurationBinder.Bind), [typeof(IConfiguration), typeof(object)])! - .Invoke(null, [configuration, options]); + BindMethod!.Invoke(null, [configuration, options]);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Infrastructure/Extensions/IConfigurationExtensions.cs` around lines 15 - 18, Cache the reflected ConfigurationBinder.Bind MethodInfo in a static readonly field on the containing extension class, initialized once with the existing signature lookup. Update DynamicBind<T> to invoke that cached field instead of calling GetMethod on every execution, preserving the current configuration and options arguments.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/Templates/Boilerplate/Bit.Boilerplate/.mcp.json`:
- Around line 15-18: Replace the mutable `@playwright/mcp`@latest reference with
one identical exact published version in both
src/Templates/Boilerplate/Bit.Boilerplate/.mcp.json (lines 15-18) and
src/Templates/Boilerplate/Bit.Boilerplate/.vscode/mcp.json (lines 15-18),
preserving the existing Playwright stdio configuration.
In
`@src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Identity/Services/AppJwtSecureDataFormat.cs`:
- Around line 34-35: Update Unprotect to clone the baseline validationParameters
on each validation, then apply the current Identity.Audience and Identity.Issuer
from appSettingsMonitor.CurrentValue before calling
JwtSecurityTokenHandler.ValidateToken. Preserve the existing baseline parameters
and use the per-call clone so runtime configuration changes are honored.
In
`@src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Identity/Services/TenantProvider.cs`:
- Around line 79-95: Update GetTenantsLookup when constructing IdsByName and
IdsByDomain to lowercase each tenant Name and Domain key before inserting them
into the dictionaries, while retaining StringComparer.OrdinalIgnoreCase and the
existing filtering behavior for empty domains.
In
`@src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Tenants/TenantConfiguration.cs`:
- Around line 34-39: Update the PostgreSQL index filter in the Tenant entity
configuration to use double-quoted identifier syntax for the Domain column
instead of single quotes, ensuring the generated column name is matched when
naming conventions apply. Keep the unique index configuration unchanged.
---
Nitpick comments:
In
`@src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Infrastructure/Extensions/IConfigurationExtensions.cs`:
- Around line 15-18: Cache the reflected ConfigurationBinder.Bind MethodInfo in
a static readonly field on the containing extension class, initialized once with
the existing signature lookup. Update DynamicBind<T> to invoke that cached field
instead of calling GetMethod on every execution, preserving the current
configuration and options arguments.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: e2ef1815-6177-4900-95b2-873115fb9f57
📒 Files selected for processing (40)
src/Templates/Boilerplate/Bit.Boilerplate/.mcp.jsonsrc/Templates/Boilerplate/Bit.Boilerplate/.vscode/mcp.jsonsrc/Templates/Boilerplate/Bit.Boilerplate/AGENTS.mdsrc/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Tenants/AddOrEditTenantModal.razorsrc/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Tenants/ManageAllTenantsPage.razorsrc/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Tenants/ManageMyTenantsPage.razorsrc/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/Program.Services.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.Services.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Build.propssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Identity/Services/AppJwtSecureDataFormat.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Identity/Services/TenantProvider.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Tenants/Tenant.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Tenants/TenantConfiguration.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Tenants/TenantController.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Tenants/TenantManagementController.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Infrastructure/RequestPipeline/ForceUpdateMiddleware.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Program.Services.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Program.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Shared/Infrastructure/Extensions/WebApplicationBuilderExtensions.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Shared/Infrastructure/Extensions/WebApplicationExtensions.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Shared/Infrastructure/Services/AppResponseCachePolicy.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Shared/ServerSharedSettings.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Web/Program.Services.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Web/Program.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Web/ServerWebSettings.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Features/Tenants/Dtos/TenantDto.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Infrastructure/Extensions/IConfigurationExtensions.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Infrastructure/Extensions/ISharedServiceCollectionExtensions.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.ar.resxsrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.de.resxsrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.es.resxsrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.fa.resxsrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.fr.resxsrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.hi.resxsrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.nl.resxsrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.resxsrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.sv.resxsrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.zh.resxsrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/SharedSettings.cs
💤 Files with no reviewable changes (3)
- src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Shared/ServerSharedSettings.cs
- src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Web/ServerWebSettings.cs
- src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/SharedSettings.cs
6333e77 to
b89fa52
Compare
|
@coderabbitai full review |
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Identity/Configurations/RoleConfiguration.cs (1)
31-37: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsolidate provider-specific
IS NULLfilters.The PR successfully abstracted the provider-specific syntax for
IS NOT NULLfilters intoHasUniqueIndexOnNullable, but identical preprocessor blocks forIS NULLfilters were left scattered across entity configurations. Consider adding a complementaryHasUniqueIndexWhereNullextension method to DRY up these remaining configurations.
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Identity/Configurations/RoleConfiguration.cs#L31-L37: Replace this conditional filter block with a call to the proposedHasUniqueIndexWhereNullhelper.src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Identity/Configurations/UserClaimConfiguration.cs#L16-L22: Replace this conditional filter block with a call to the proposedHasUniqueIndexWhereNullhelper.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Identity/Configurations/RoleConfiguration.cs` around lines 31 - 37, Introduce the complementary HasUniqueIndexWhereNull extension alongside HasUniqueIndexOnNullable, handling provider-specific IS NULL syntax internally. In RoleConfiguration.cs lines 31-37 and UserClaimConfiguration.cs lines 16-22, replace each conditional HasFilter block with the new helper while preserving the existing unique index on the nullable TenantId column.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Infrastructure/Extensions/IConfigurationExtensions.cs`:
- Around line 10-12: The bind delegate in IConfigurationExtensions must not use
reflection, since this prevents configuration binding from being visible to AOT
and trimming. Replace the reflected ConfigurationBinder.Bind call with
source-generated binding, and address any third-party obsolete-property warnings
through targeted project warning suppression or explicit property binding.
Ensure SentryOptions, MemoryCacheOptions, and ForwardedHeadersOptions continue
binding correctly across all affected projects.
---
Nitpick comments:
In
`@src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Identity/Configurations/RoleConfiguration.cs`:
- Around line 31-37: Introduce the complementary HasUniqueIndexWhereNull
extension alongside HasUniqueIndexOnNullable, handling provider-specific IS NULL
syntax internally. In RoleConfiguration.cs lines 31-37 and
UserClaimConfiguration.cs lines 16-22, replace each conditional HasFilter block
with the new helper while preserving the existing unique index on the nullable
TenantId column.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 49661f72-ec63-4eaf-a0ec-44b38141574d
📒 Files selected for processing (40)
src/Templates/Boilerplate/Bit.Boilerplate/.mcp.jsonsrc/Templates/Boilerplate/Bit.Boilerplate/.vscode/mcp.jsonsrc/Templates/Boilerplate/Bit.Boilerplate/AGENTS.mdsrc/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Tenants/AddOrEditTenantModal.razorsrc/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Tenants/ManageAllTenantsPage.razorsrc/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Tenants/ManageMyTenantsPage.razorsrc/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/MauiProgram.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/Program.Services.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Windows/Program.Services.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Build.propssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Identity/Configurations/RoleConfiguration.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Identity/Configurations/UserClaimConfiguration.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Identity/Configurations/UserConfiguration.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Identity/Services/TenantProvider.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/PushNotification/PushNotificationSubscriptionConfiguration.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Tenants/Tenant.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Tenants/TenantConfiguration.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Tenants/TenantController.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Features/Tenants/TenantManagementController.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Infrastructure/Extensions/EntityTypeBuilderExtensions.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Program.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Shared/Infrastructure/Extensions/WebApplicationExtensions.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Shared/ServerSharedSettings.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Web/Program.Services.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Web/Program.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Web/ServerWebSettings.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Features/Tenants/Dtos/TenantDto.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Infrastructure/Extensions/IConfigurationExtensions.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Infrastructure/Extensions/ISharedServiceCollectionExtensions.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.ar.resxsrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.de.resxsrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.es.resxsrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.fa.resxsrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.fr.resxsrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.hi.resxsrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.nl.resxsrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.resxsrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.sv.resxsrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.zh.resxsrc/Templates/Boilerplate/Bit.Boilerplate/src/Shared/SharedSettings.cs
💤 Files with no reviewable changes (3)
- src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/SharedSettings.cs
- src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Shared/ServerSharedSettings.cs
- src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Web/ServerWebSettings.cs
closes #12679
Summary by CodeRabbit
New Features
Bug Fixes
Documentation