You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* docs: ViewState Phase 5 analyzer docs, AutoPostBack guide, sample updates
- Analyzers.md: BWFC002/003 severity updated to Info, added BWFC025 section,
updated prioritization guide and .editorconfig examples
- ViewStateAndPostBack.md: Added AutoPostBack (SSR) section with usage guide
- ViewState sample page: Modernized to showcase ViewStateDictionary type-safe
API, IsPostBack detection, and graduating-off-ViewState patterns
- Added analyzer screenshot placeholders with capture instructions
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: Add AnalyzerDemo page for VS screenshot captures
Adds AnalyzerDemo.razor.cs in AfterDepartmentPortal with patterns that
trigger BWFC002, BWFC003, and BWFC025 analyzers. Also adds direct
analyzer ProjectReference so diagnostics appear in VS.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: Add VS analyzer screenshots for BWFC002 and BWFC003
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: Update Playwright test for renamed ViewState button
The ViewState sample page was modernized button changed from
'Click Me (ViewState)' to 'Increment'. Update test selector to match.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@@ -30,15 +30,16 @@ Once installed, diagnostics appear automatically in Visual Studio's Error List a
30
30
| Rule ID | Severity | Name | What It Detects |
31
31
|---------|----------|------|-----------------|
32
32
|[BWFC001](#bwfc001-missing-parameter-attribute)| ⚠️ Warning | Missing `[Parameter]` Attribute | Public properties on WebControl subclasses without `[Parameter]`|
|[BWFC025](#bwfc025-non-serializable-viewstate-type)| ⚠️ Warning | Non-Serializable ViewState Type |`ViewState["key"]` assignments with non-JSON-serializable types |
42
43
43
44
---
44
45
@@ -90,16 +91,16 @@ Adds `[Parameter]` to the property and inserts `using Microsoft.AspNetCore.Compo
90
91
91
92
## BWFC002: ViewState Usage
92
93
93
-
**Severity:**⚠️ Warning
94
+
**Severity:**ℹ️ Info
94
95
**Category:** Usage
95
96
96
97
### What It Detects
97
98
98
-
`ViewState["key"]` and `this.ViewState["key"]` element-access patterns in code-behind. Blazor has no ViewState mechanism — it uses in-memory component state instead.
99
+
`ViewState["key"]` and `this.ViewState["key"]` element-access patterns in code-behind. This diagnostic is now informational because the BWFC `ViewStateDictionary` shim provides working ViewState support during migration. The analyzer still highlights these patterns to encourage eventual adoption of native Blazor state management.
99
100
100
101
### Why It Matters
101
102
102
-
ViewState was the persistence mechanism for Web Forms page lifecycle. In Blazor, components live in memory on the server (Blazor Server) or in the browser (Blazor WebAssembly). State is naturally preserved across re-renders as regular C# fields and properties — no serialization needed. Any leftover `ViewState` access will either fail at compile time or use the BWFC compatibility shim, which is meant as a stepping stone, not a long-term solution.
103
+
ViewState is now supported as a working migration shim via `ViewStateDictionary` — your `ViewState["key"]` code will compile and run correctly in Blazor. However, native Blazor patterns (component fields, `[Parameter]` properties, cascading values) are preferred for new code because they are type-safe, avoid serialization overhead, and are idiomatic Blazor.
The [ViewState utility documentation](../UtilityFeatures/ViewState.md) explains the BWFC compatibility shim and the recommended path to component state.
144
145
146
+
!!! info "Severity Reduced (Phase 4)"
147
+
This analyzer was reduced from Warning to Info because the BWFC `ViewStateDictionary` shim now provides working ViewState support. The code fix still suggests migrating to native Blazor patterns, which remains the recommended long-term approach.
148
+
149
+
<!-- TODO: Add Visual Studio screenshot showing BWFC002 Info squiggle on ViewState["key"] usage -->
150
+
<!-- Screenshot should show: the green info squiggle under ViewState["SortDirection"], the lightbulb, and the tooltip message -->
151
+
{ .analyzer-screenshot }
152
+
145
153
---
146
154
147
155
## BWFC003: IsPostBack Usage
148
156
149
-
**Severity:**⚠️ Warning
157
+
**Severity:**ℹ️ Info
150
158
**Category:** Usage
151
159
152
160
### What It Detects
153
161
154
-
References to `IsPostBack` and `Page.IsPostBack` in code-behind. Blazor does not use the postback model — it uses component lifecycle methods instead.
162
+
References to `IsPostBack` and `Page.IsPostBack` in code-behind. This diagnostic is now informational because BWFC provides mode-adaptive `IsPostBack` support that works correctly during migration.
155
163
156
164
### Why It Matters
157
165
158
-
In Web Forms, `IsPostBack`distinguished between the initial page load and subsequent postbacks. In Blazor, this distinction maps to lifecycle methods:
166
+
`IsPostBack`is now supported as a working migration shim — in SSR mode it checks `HttpMethods.IsPost()`, and in Interactive mode it tracks initialization state. Your existing `if (!IsPostBack)` guards will work correctly. However, the idiomatic Blazor approach is to use lifecycle methods directly:
This analyzer was reduced from Warning to Info because BWFC now provides mode-adaptive `IsPostBack` support (SSR checks HTTP POST method, Interactive tracks initialization state). The code fix still suggests lifecycle methods, which is the idiomatic Blazor approach.
212
+
213
+
<!-- TODO: Add Visual Studio screenshot showing BWFC003 Info squiggle on IsPostBack usage -->
214
+
<!-- Screenshot should show: the green info squiggle under IsPostBack, the lightbulb, and the tooltip message -->
215
+
{ .analyzer-screenshot }
216
+
202
217
---
203
218
204
219
## BWFC004: Response.Redirect Usage
@@ -709,6 +724,79 @@ Use the `InputFile` component:
709
724
710
725
---
711
726
727
+
## BWFC025: Non-Serializable ViewState Type
728
+
729
+
**Severity:** ⚠️ Warning
730
+
**Category:** Usage
731
+
732
+
### What It Detects
733
+
734
+
Assignments to `ViewState["key"]` or `ViewState.Set<T>()` where the value type is unlikely to be JSON-serializable. The analyzer flags:
735
+
736
+
| Type Pattern | Why It's Flagged |
737
+
|---|---|
738
+
|`IDisposable` implementations | Streams, DB connections, HttpClient — not safe to serialize |
739
+
| Delegates and event handlers | Cannot be serialized to JSON |
740
+
|`System.Data.DataSet` / `DataTable`| Common Web Forms pattern, but complex object graphs fail with System.Text.Json |
741
+
|`System.Web.*` types | ASP.NET classic types not available in .NET 8+ |
742
+
|`System.IO.Stream*` types | OS handles cannot be serialized |
743
+
|`System.Net.*` types | Network objects cannot be serialized |
744
+
745
+
### Why It Matters
746
+
747
+
In SSR mode, BWFC serializes `ViewStateDictionary` contents to JSON using `System.Text.Json` and embeds them in a hidden form field. Types that lack a parameterless constructor, have non-public properties, or represent OS handles will fail at runtime with a `JsonException`.
748
+
749
+
In Interactive Server mode, ViewState is kept in memory and serialization is skipped — so the same code may work interactively but fail in SSR. This analyzer catches the problem at compile time.
750
+
751
+
### Example
752
+
753
+
=== "Before (triggers BWFC025)"
754
+
```csharp
755
+
protected override void OnInitialized()
756
+
{
757
+
// ⚠️ MemoryStream implements IDisposable — not JSON-serializable
758
+
ViewState["ReportData"] = new MemoryStream();
759
+
760
+
// ⚠️ DataTable has complex internal structure — fails with System.Text.Json
This analyzer does not have an automatic code fix because the correct replacement depends on your specific data structure. Common strategies:
781
+
782
+
-**Streams** → Store `byte[]` or `string` (base64)
783
+
-**DataTable** → Convert to `List<T>` of POCOs
784
+
-**Complex objects** → Create a DTO with public properties and a parameterless constructor
785
+
-**Delegates** → Don't store in ViewState; use component fields instead
786
+
787
+
!!! tip "Check Serialization"
788
+
You can verify a type serializes correctly by testing:
789
+
```csharp
790
+
var json = System.Text.Json.JsonSerializer.Serialize(myValue);
791
+
var roundTrip = System.Text.Json.JsonSerializer.Deserialize<MyType>(json);
792
+
```
793
+
794
+
<!-- TODO: Add Visual Studio screenshot showing BWFC025 Warning squiggle on ViewState assignment with DataTable -->
795
+
<!-- Screenshot should show: the yellow warning squiggle under the assignment, tooltip showing "ViewState assignment stores 'System.Data.DataTable' which may not be JSON-serializable" -->
796
+
{ .analyzer-screenshot }
797
+
798
+
---
799
+
712
800
## Using Analyzers in CI/CD
713
801
714
802
The analyzers integrate seamlessly with `dotnet build` and CI/CD pipelines. You can configure severity levels per rule and fail the build on violations.
@@ -720,18 +808,19 @@ The analyzers integrate seamlessly with `dotnet build` and CI/CD pipelines. You
720
808
721
809
# Mandatory rules: fail the build
722
810
dotnet_diagnostic.BWFC001.severity = error
723
-
dotnet_diagnostic.BWFC003.severity = error
724
811
dotnet_diagnostic.BWFC004.severity = error
725
812
726
813
# Important patterns: treat as warnings
727
-
dotnet_diagnostic.BWFC002.severity = warning
728
814
dotnet_diagnostic.BWFC005.severity = warning
729
815
dotnet_diagnostic.BWFC011.severity = warning
730
816
dotnet_diagnostic.BWFC012.severity = warning
731
817
dotnet_diagnostic.BWFC013.severity = warning
732
818
dotnet_diagnostic.BWFC014.severity = warning
819
+
dotnet_diagnostic.BWFC025.severity = warning
733
820
734
821
# Informational patterns: visible but don't block build
822
+
dotnet_diagnostic.BWFC002.severity = suggestion
823
+
dotnet_diagnostic.BWFC003.severity = suggestion
735
824
dotnet_diagnostic.BWFC010.severity = suggestion
736
825
```
737
826
@@ -770,10 +859,10 @@ These patterns prevent your components from working at all:
Copy file name to clipboardExpand all lines: docs/UtilityFeatures/ViewStateAndPostBack.md
+83Lines changed: 83 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -483,6 +483,89 @@ A common migration pattern is to start with SSR (traditional form posts) and gra
483
483
484
484
---
485
485
486
+
## AutoPostBack (SSR)
487
+
488
+
### What It Is
489
+
490
+
In Web Forms, `AutoPostBack="true"` on controls like `<asp:DropDownList>`, `<asp:CheckBox>`, and `<asp:TextBox>` caused the form to automatically submit when the user changed the value. This triggered a full page postback.
491
+
492
+
In BWFC, AutoPostBack is mode-adaptive:
493
+
494
+
| Render Mode | Behavior |
495
+
|---|---|
496
+
|**SSR (Static)**| Emits `onchange="this.form.submit()"` on the HTML element — mimics the Web Forms postback |
497
+
|**Interactive Server**| Uses Blazor's native `@onchange` event binding — no form submission needed |
498
+
499
+
### Supported Controls
500
+
501
+
AutoPostBack is supported on these controls:
502
+
503
+
-`DropDownList`
504
+
-`CheckBox`
505
+
-`TextBox`
506
+
-`RadioButton`
507
+
-`ListBox`
508
+
-`CheckBoxList`
509
+
-`RadioButtonList`
510
+
511
+
### Usage
512
+
513
+
Set `AutoPostBack="true"` on any supported control. In SSR mode, changing the control value submits the enclosing `<form>`:
The `BaseWebFormsComponent.GetAutoPostBackAttributes()` method returns a dictionary of HTML attributes when AutoPostBack conditions are met:
548
+
549
+
1. The control has `AutoPostBack = true`
550
+
2. The current render mode is SSR (not Interactive)
551
+
552
+
When both conditions are true, the method returns `{ "onchange": "this.form.submit()" }`, which is applied to the HTML input element via Blazor's `@attributes` splatting.
553
+
554
+
When either condition is false, the method returns an empty dictionary and no extra attributes are emitted.
555
+
556
+
### Combining with ViewState
557
+
558
+
AutoPostBack and ViewState work together naturally in SSR:
559
+
560
+
1. User changes a DropDownList value
561
+
2.`onchange="this.form.submit()"` submits the form
562
+
3. The form POST includes both the new value AND the ViewState hidden fields
563
+
4. On the server, `IsPostBack` is `true`, ViewState is deserialized, and the new value is available
564
+
565
+
This mirrors the Web Forms lifecycle without requiring any JavaScript interop or SignalR connection.
0 commit comments