Skip to content

Latest commit

 

History

History
228 lines (168 loc) · 9.93 KB

File metadata and controls

228 lines (168 loc) · 9.93 KB

Migration Instructions for [Your Project Name]

Your Application Context

  • Application name: [Your App Name]
  • Page count: [N] .aspx pages, [N] .ascx user controls, [N] .master pages
  • Primary controls used: [e.g., GridView, ListView, FormView, Login controls]
  • Data access pattern: [e.g., SqlDataSource, EntityDataSource, ObjectDataSource, inline DbContext]
  • Authentication: [e.g., ASP.NET Membership, ASP.NET Identity, Forms Auth, Windows Auth]
  • Session state usage: [Heavy / Moderate / Light / None]
  • Target framework: .NET [8/9/10]

BWFC Core Migration Rules

When migrating Web Forms markup to Blazor using BWFC, apply these rules in order:

1. Remove Web Forms Boilerplate

  • Remove all runat="server" attributes
  • Remove all asp: tag prefixes (<asp:Button><Button>)
  • Remove <%@ Page %>, <%@ Control %>, <%@ Master %> directives
  • Add @page "/route" directive at the top of each page
  • Remove <asp:Content> wrappers — the page body IS the content
  • Remove <form runat="server"> wrappers entirely

2. Convert Expressions

Web Forms Blazor
<%: expression %> @(expression)
<%= expression %> @(expression)
<%# Item.Property %> @context.Property (in templates)
<%# Eval("Property") %> @context.Property
<%# Bind("Property") %> @bind-Value="context.Property"
<%-- comment --%> @* comment *@

3. Convert Data Binding

  • Replace ItemType="Namespace.Type" with TItem="Type"
  • When original used SelectMethod: Preserve as delegate reference: SelectMethod="@service.GetItems" (BWFC's DataBoundComponent auto-populates Items)
  • When original used DataSource/DataBind(): Replace with Items="propertyName" (collections) or DataItem="propertyName" (single record)
  • Load data in OnInitializedAsync (only when using Items binding):
@inject IYourService YourService

private List<YourType> items = new();

protected override async Task OnInitializedAsync()
{
    items = await YourService.GetItemsAsync();
}

⚠️ Do NOT convert SelectMethod to Items= binding — BWFC natively supports SelectMethod as a delegate.

4. Convert Templates

Add Context="Item" to all data templates:

<ItemTemplate Context="Item">
    @Item.PropertyName
</ItemTemplate>

5. Convert Code-Behind

Web Forms Blazor
Page_Load(sender, e) OnInitializedAsync()
if (!IsPostBack) Works AS-IS via WebFormsPageBase; optionally simplify
Page_PreRender OnParametersSetAsync()
Response.Redirect("~/path") Works AS-IS via ResponseShim (auto-strips ~/ and .aspx); or use NavigationManager.NavigateTo("/path")
Page.Title = "X" Works AS-IS via WebFormsPageBase
Session["key"] Works AS-IS via SessionShim; or use scoped service / ProtectedSessionStorage
Request.Form["key"] Works AS-IS via FormShim + <WebFormsForm> component
Request.QueryString["key"] Works AS-IS via RequestShim; or use [SupplyParameterFromQuery]
Server.MapPath("~/path") Works AS-IS via ServerShim
Cache["key"] Works AS-IS via CacheShim
Page.ClientScript.RegisterStartupScript(...) Works AS-IS via ClientScriptShim
ViewState["key"] Works AS-IS via ViewStateDictionary; or use component field

6. Convert Event Handlers

// Web Forms
protected void Button_Click(object sender, EventArgs e) { }

// Blazor
private void Button_Click() { }

7. Convert URLs

  • Replace ~/ with / in all URL references
  • Replace NavigateUrl="~/path" with NavigateUrl="/path"

8. Convert Master Page → Layout

  • <asp:ContentPlaceHolder ID="MainContent">@Body
  • Add @inherits LayoutComponentBase to the layout file
  • <asp:ScriptManager><ScriptManager /> (renders nothing — correct)

Control-Specific Notes

Control Your Usage Migration Notes
GridView [e.g., ProductGrid on Products.aspx] Items="products" + TItem="Product"
ListView [e.g., CategoryList on Default.aspx] Items="categories" + TItem="Category"
FormView [e.g., ProductDetail on Detail.aspx] DataItem="product" + TItem="Product"
TextBox [e.g., Login form fields] Add @bind-Text="model.Property"
DropDownList [e.g., Category filter] Bind Items + @bind-SelectedValue
Validators [e.g., Login/Register forms] Nearly 1:1 — wrap form in <EditForm>

Architecture Decisions Made

Data Access

[Describe your data access approach]

Authentication

[Describe your auth approach]

Session State

[Describe your session state approach]

Navigation / Routing

[Describe your routing strategy]


Routing Table

Original URL Blazor Route Page File
/Default.aspx @page "/" Pages/Index.razor
/Products.aspx @page "/Products" Pages/Products.razor
/Products/Detail.aspx?id=5 @page "/Products/{ProductId:int}" Pages/ProductDetail.razor

Attributes to Remove Silently

When Copilot encounters these attributes during migration, remove them without comment — they have no Blazor equivalent:

runat="server", AutoEventWireup, CodeBehind, CodeFile, Inherits (usually), EnableViewState, ViewStateMode, ValidateRequest, MaintainScrollPositionOnPostBack, ClientIDMode, EnableTheming, SkinID


Common Gotchas

  1. No ViewState — Blazor components maintain state in fields/properties. ViewStateDictionary shim available for compile-compat via WebFormsPageBase.ViewState.
  2. IsPostBack works AS-ISWebFormsPageBase provides IsPostBack (SSR: checks HTTP method; Interactive: tracks render count). if (!IsPostBack) compiles and runs correctly.
  3. No DataSource controlsSqlDataSource, ObjectDataSource, EntityDataSource must be replaced with injected services.
  4. Template Context — In Web Forms, Item is implicitly available. In BWFC, add Context="Item" on template elements.
  5. ID Rendering — Blazor doesn't generate client IDs like ctl00_MainContent_Grid. If CSS/JS targets these IDs, switch to class selectors.
  6. String formatting — Replace <%#: string.Format("{0:C}", Item.Price) %> with @Item.Price.ToString("C").
  7. TextBox TextMode — The value is Multiline (not MultiLine) in BWFC.
  8. VisibilityVisible="false" works in BWFC, but prefer @if (condition) for dynamic visibility.
  9. ClientScript migrationPage.ClientScript.RegisterStartupScript() works via ClientScriptShim. For new code, prefer IJSRuntime.
  10. Form POST data — Use <WebFormsForm OnSubmit="SetRequestFormData"> to enable Request.Form["key"] in interactive mode.
  11. Server.Transfer has NO shim — There is no BWFC shim for Server.Transfer(). Use NavigationManager.NavigateTo() instead. Server.Transfer does server-side URL rewriting which doesn't exist in Blazor.
  12. Server.GetLastError/ClearError have NO shim — Use ILogger and middleware-based error handling (app.UseExceptionHandler).
  13. ThreadAbortException is dead code — Web Forms throws ThreadAbortException on Response.Redirect(url, true). Blazor does not. Any catch (ThreadAbortException) blocks are dead code after migration — review and remove.
  14. HttpContext.Current doesn't work in Blazor — Static HttpContext.Current.Session["key"] must be replaced with Session["key"] (on pages) or constructor-injected SessionShim (in non-page classes). The CLI tool handles this replacement automatically.

References