Context
DepartmentPortal's Web.config registers tag prefixes at the namespace level, not via src= file paths:
<pages>
<controls>
<add tagPrefix="uc" namespace="DepartmentPortal.Controls" assembly="DepartmentPortal" />
<add tagPrefix="local" namespace="DepartmentPortal.Controls" assembly="DepartmentPortal" />
<add tagPrefix="uc" src="~/Controls/QuickStats.ascx" tagName="QuickStats" />
</controls>
</pages>
The first two entries use namespace= + assembly= to resolve any type in the DepartmentPortal.Controls namespace as a tag under the given prefix. This means <local:SectionPanel>, <local:EmployeeDataGrid>, <uc:EmployeeCard>, etc. all resolve to code-only C# server control classes — there is no .ascx file involved.
The CLI currently only handles src=-based control registrations (the third entry above, which points to an .ascx file). Namespace-level registrations are silently ignored, leaving all local:TypeName and uc:TypeName references in page markup unresolved during migration.
Impact
Every page in DepartmentPortal that uses a local: or uc: prefixed code-only control will have those tags pass through the pipeline untransformed — resulting in invalid Blazor markup that references non-existent components.
Affected pages include: Announcements.aspx, Resources.aspx, Employees.aspx, EmployeeDetail.aspx, Training.aspx, Admin/ManageEmployees.aspx.
Proposed Fix
Part 1 — Extend WebConfigTransformer
Parse <add tagPrefix namespace=... assembly=...> entries and build a prefix → namespace map in the migration context. This map should be passed into the markup transform pipeline alongside the existing src=-based control map.
Part 2 — New LocalTagNamespaceResolutionTransform (markup transform)
Create a new IMarkupTransform that:
- Receives the
prefix → namespace map from Part 1
- Scans markup for
<prefix:TypeName ...> elements where prefix is a registered namespace prefix
- Resolves the type by looking up
TypeName in the discovered code-only control stubs (emitted by CodeOnlyControlScaffolder)
- Rewrites
<local:SectionPanel ...> → <SectionPanel ...> (or the correct Blazor component reference)
- Handles both self-closing and block-level forms
Web.config Pattern Being Addressed
<!-- Namespace-level (NEW — not currently handled) -->
<add tagPrefix="local" namespace="DepartmentPortal.Controls" assembly="DepartmentPortal" />
<!-- Src-level (existing — already handled) -->
<add tagPrefix="uc" src="~/Controls/QuickStats.ascx" tagName="QuickStats" />
Registration
Per project conventions, the new transform must be registered in both:
src/BlazorWebFormsComponents.Cli/Program.cs (DI registration)
tests/BlazorWebFormsComponents.Cli.Tests/TestHelpers.cs (CreateDefaultPipeline())
Acceptance Criteria
Notes
This is Tier 1 Critical Blocker P2 from the DepartmentPortal gap analysis. Without this, every local: prefixed markup tag on 6 DepartmentPortal pages passes through untransformed, producing invalid Blazor markup.
Context
DepartmentPortal's
Web.configregisters tag prefixes at the namespace level, not viasrc=file paths:The first two entries use
namespace=+assembly=to resolve any type in theDepartmentPortal.Controlsnamespace as a tag under the given prefix. This means<local:SectionPanel>,<local:EmployeeDataGrid>,<uc:EmployeeCard>, etc. all resolve to code-only C# server control classes — there is no.ascxfile involved.The CLI currently only handles
src=-based control registrations (the third entry above, which points to an.ascxfile). Namespace-level registrations are silently ignored, leaving alllocal:TypeNameanduc:TypeNamereferences in page markup unresolved during migration.Impact
Every page in DepartmentPortal that uses a
local:oruc:prefixed code-only control will have those tags pass through the pipeline untransformed — resulting in invalid Blazor markup that references non-existent components.Affected pages include: Announcements.aspx, Resources.aspx, Employees.aspx, EmployeeDetail.aspx, Training.aspx, Admin/ManageEmployees.aspx.
Proposed Fix
Part 1 — Extend
WebConfigTransformerParse
<add tagPrefix namespace=... assembly=...>entries and build aprefix → namespacemap in the migration context. This map should be passed into the markup transform pipeline alongside the existingsrc=-based control map.Part 2 — New
LocalTagNamespaceResolutionTransform(markup transform)Create a new
IMarkupTransformthat:prefix → namespacemap from Part 1<prefix:TypeName ...>elements whereprefixis a registered namespace prefixTypeNamein the discovered code-only control stubs (emitted byCodeOnlyControlScaffolder)<local:SectionPanel ...>→<SectionPanel ...>(or the correct Blazor component reference)Web.config Pattern Being Addressed
Registration
Per project conventions, the new transform must be registered in both:
src/BlazorWebFormsComponents.Cli/Program.cs(DI registration)tests/BlazorWebFormsComponents.Cli.Tests/TestHelpers.cs(CreateDefaultPipeline())Acceptance Criteria
WebConfigTransformerparses<add tagPrefix namespace=... assembly=...>entries and builds a prefix→namespace mapLocalTagNamespaceResolutionTransformis implemented and registered in bothProgram.csandTestHelpers.cs<local:SectionPanel>,<local:EmployeeDataGrid>,<uc:EmployeeCard>etc. are correctly rewritten to Blazor component referencesCodeOnlyControlScaffolderoutput (see companion issue)tests/BlazorWebFormsComponents.Cli.Tests/Notes
This is Tier 1 Critical Blocker P2 from the DepartmentPortal gap analysis. Without this, every
local:prefixed markup tag on 6 DepartmentPortal pages passes through untransformed, producing invalid Blazor markup.