feat: ViewState + PostBack shim - Phase 1 core implementation#503
feat: ViewState + PostBack shim - Phase 1 core implementation#503csharpfritz wants to merge 6 commits intoFritzAndFriends:devfrom
Conversation
Implements the core ViewState/PostBack infrastructure per the approved architecture proposal: - ViewStateDictionary: IDictionary<string, object?> implementation with null-safe indexer (Web Forms compat), GetValueOrDefault<T>/Set<T> convenience methods, IsDirty tracking, IDataProtector-based Serialize/Deserialize, JsonElement type coercion for round-trip fidelity - BaseWebFormsComponent: ViewState upgraded from Dictionary<string,object> to ViewStateDictionary, [Obsolete] removed, IsPostBack with mode-adaptive logic (SSR: HTTP method check, Interactive: _hasInitialized flag), CurrentRenderMode/IsHttpContextAvailable properties, RenderViewStateField for SSR hidden field emission, IDataProtectionProvider injection, ViewState deserialization from form POST in OnInitializedAsync - WebFormsPageBase: ViewState upgraded to ViewStateDictionary, [Obsolete] removed, IsPostBack with same mode-adaptive logic, OnInitialized override to track _hasInitialized - WebFormsRenderMode enum: StaticSSR, InteractiveServer Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…WebFormsRenderMode ViewStateDictionaryTests.cs (48 tests): - Basic dictionary operations (indexer, ContainsKey, Remove, Clear, Count) - Null safety (missing key returns null, null value storage) - Type coercion (int/bool cast, Set<T>/GetValueOrDefault<T>) - IsDirty tracking (creation, set, add, remove, clear, MarkClean) - Serialization roundtrip with EphemeralDataProtectionProvider - JSON type coercion after deserialization (int, bool, string, double, DateTime) - Edge cases (100K strings, special characters in keys) - IDictionary<string, object?> interface compliance - Web Forms migration pattern validation (ViewState-backed property) - LoadFrom merge behavior IsPostBackTests.cs (14 tests): - BaseWebFormsComponent: interactive mode (false during init, true after) - BaseWebFormsComponent: SSR GET=false, POST=true - WebFormsPageBase: same pattern for both modes - Guard pattern (!IsPostBack) block execution/skip WebFormsRenderModeTests.cs (7 tests): - Enum has StaticSSR and InteractiveServer (exactly 2 values) - CurrentRenderMode returns StaticSSR with HttpContext - CurrentRenderMode returns InteractiveServer without HttpContext - IsHttpContextAvailable mirrors HttpContext presence Also adds InternalsVisibleTo for test project access to internal ViewStateDictionary members (IsDirty, MarkClean, Serialize, Deserialize). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- ViewStateDictionary: IDictionary<string, object?> with null-safe indexer, type coercion (JsonElement T), dirty tracking, IDataProtector serialize/deserialize for SSR hidden field persistence - IsPostBack: mode-adaptive (SSR: HTTP method check, Interactive: lifecycle) - WebFormsRenderMode enum (StaticSSR, InteractiveServer) - RenderViewStateField for SSR hidden field emission - DataProtectionProvider resolved lazily (optional, backward-compatible) - Removed [Obsolete] from ViewState (now a real feature) - Updated legacy tests for new behavior (null for missing keys, IsPostBack true after init in Interactive mode) - 73 new contract tests + 2588 total tests passing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…cision consolidation Session: 2026-03-24T15-30-viewstate-phase1-complete Requested by: Jeffrey T. Fritz Changes: - Added orchestration log: 2026-03-24T15-30-coordinator.md (ViewState test fix & commit) - Added session log: 2026-03-24T15-30-viewstate-phase1-complete.md (full Phase 1 summary) - Merged 7 inbox decisions decisions.md (ViewState/PostBack architecture, NuGet assets, user directives, AfterDepartmentPortal setup) - Deleted inbox files (copilot-directive-*, cyclops-viewstate-impl, forge-nuget-asset-strategy, forge-viewstate-postback-architecture, jubilee-runnable-demo, rogue-viewstate-tests) - Updated cross-agent history: Cyclops, Rogue, Forge (team updates appended with ViewState Phase 1 outcomes) Related commits: - 1bf5cde: ViewState Phase 1 implementation (2588/2588 tests passing) - f7119a0: Cyclops Phase 1 impl - 879678e: Rogue tests - 6ca64de: Rogue history - be2794a: formatting fix All Phase 1 work consolidated. Phase 2 (SSR persistence, AutoPostBack, analyzers, docs) planned for 7 weeks. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| [Fact] | ||
| public void ContainsKey_MissingKey_ReturnsFalse() | ||
| { | ||
| var dict = new ViewStateDictionary(); |
Check failure
Code scanning / CodeQL
Container contents are never initialized Error test
| [Fact] | ||
| public void Indexer_MissingKey_ReturnsNull() | ||
| { | ||
| var dict = new ViewStateDictionary(); |
Check failure
Code scanning / CodeQL
Container contents are never initialized Error test
| [Fact] | ||
| public void IsDirty_FalseOnCreation() | ||
| { | ||
| var dict = new ViewStateDictionary(); |
Check failure
Code scanning / CodeQL
Container contents are never initialized Error test
| [Fact] | ||
| public void Add_DuplicateKey_Throws() | ||
| { | ||
| var dict = new ViewStateDictionary(); |
Check failure
Code scanning / CodeQL
Container contents are never accessed Error test
| [Fact] | ||
| public void TryGetValue_MissingKey_ReturnsFalse() | ||
| { | ||
| var dict = new ViewStateDictionary(); |
Check failure
Code scanning / CodeQL
Container contents are never initialized Error test
| { | ||
| var dict = new ViewStateDictionary(); | ||
|
|
||
| (dict is IDictionary<string, object?>).ShouldBeTrue(); |
Check warning
Code scanning / CodeQL
Useless type test Warning test
| dict["b"] = 2; | ||
|
|
||
| var count = 0; | ||
| foreach (var kvp in dict) |
Check warning
Code scanning / CodeQL
Useless assignment to local variable Warning test
| public void CurrentRenderMode_WithoutHttpContext_ReturnsInteractiveServer() | ||
| { | ||
| var mock = new Mock<IHttpContextAccessor>(); | ||
| mock.Setup(x => x.HttpContext).Returns((HttpContext?)null); |
Check warning
Code scanning / CodeQL
Useless upcast Warning test
| public void IsHttpContextAvailable_WithoutHttpContext_ReturnsFalse() | ||
| { | ||
| var mock = new Mock<IHttpContextAccessor>(); | ||
| mock.Setup(x => x.HttpContext).Returns((HttpContext?)null); |
Check warning
Code scanning / CodeQL
Useless upcast Warning test
|
|
||
| dict["nullable"] = null; | ||
|
|
||
| dict.ContainsKey("nullable").ShouldBeTrue(); |
Check notice
Code scanning / CodeQL
Inefficient use of ContainsKey Note test
Summary
Phase 1 of the ViewState + PostBack shim infrastructure for near-zero-change ASCX migration.
Included
Breaking changes
See dev-docs/architecture/ViewState-PostBack-Shim-Proposal.md for the full 5-phase plan.