Microsoft's first .NET 11 release candidate is supported for production use as the platform moves toward its Nov. 10 launch. Most RC1 coverage is about C# 15, which RC1 makes the default language version for projects that target .NET 11. For teams moving VB6, PowerBuilder, Delphi or other legacy apps onto .NET, a smaller addition matters more: a new package of Blazor components for building agent interfaces.
This post covers what's in the package, why migrated applications are well placed to use it, and why you should add it after the migration rather than during it.
The package is Microsoft.AspNetCore.Components.AI. It includes an initial set of Blazor AI components for streaming chat, rich-text and tool rendering, human approval flows, and typed, shared, and predictive UI state. One caveat up front: the package is a prerelease, experimental package throughout .NET 11. Plan to prototype with it, not ship on it.
The core pieces:
UIAgent wraps any IChatClient from Microsoft.Extensions.AI and turns its streamed output into renderable content blocks.ChatPage gives you a working conversation UI out of the box.FunctionApprovalBlock represents a function call that is waiting for user approval. In a legacy line-of-business app, the business rules usually live inside event handlers. The credit-hold logic sits in cmdCreditHold_Click. It reads text boxes directly and depends on module-level globals. An agent can't call that code. Neither can a test harness, and neither can a new UI.
A deterministic migration pulls those rules out into ordinary C# methods with typed parameters, and that's the shape an agent needs to call something as a tool. The migration work you're already doing is what makes the agent layer possible. Without it, you'd be asking a model to operate a UI it can't see, against logic nobody can isolate.
It's tempting to redesign the application into an agent-driven workspace during the migration. Don't.
Your users have run these screens for twenty years, and on day one they need them to behave the same way. Your test strategy also depends on comparing old and new behavior, which only works if the behavior is supposed to match. Changing the interaction model mid-migration removes both safety nets at once.
The better sequence:
Here's a migrated method. It's illustrative, but it's the typical shape once logic comes out of a form:
csharp
// Migrated from cmdCreditHold_Click in frmCustomer.frm. // Business rules preserved; UI dependencies removed. public sealed class CustomerService(AppDbContext db) { public async Task<CreditHoldResult> ApplyCreditHoldAsync( string customerId, string reason, CancellationToken ct = default) { // Same validation and state transitions as the VB6 handler, // now callable from a form, a test, or an agent. } }
On the agent server, you expose that method as a tool and mark it as requiring approval. With Microsoft Agent Framework, the server decides which functions require approval, and AG-UI transports the request and decision.
In the Blazor app, you point IChatClient at that agent:
builder.Services.AddHttpClient<IChatClient>(httpClient => new AGUIChatClient(new(httpClient, "https://your-host/agent")));
Then you render the approval step:
@rendermode InteractiveServer @using Microsoft.AspNetCore.Components.AI @using Microsoft.Extensions.AI @implements IDisposable @inject IChatClient ChatClient <ChatPage Agent="agent" Placeholder="Ask about a customer account..."> <MessageListContent> <BlockRenderer TBlock="FunctionApprovalBlock" Context="approval"> <p>The assistant wants to run <code>@approval.ToolName</code>.</p> <button @onclick="approval.Approve">Approve</button> <button @onclick="() => approval.Reject()">Reject</button> </BlockRenderer> </MessageListContent> </ChatPage> @code { private UIAgent agent = default!; protected override void OnInitialized() => agent = new UIAgent(ChatClient); public void Dispose() => agent.Dispose(); }
The conversation pauses until the UI calls Approve or Reject. The model interprets the request and proposes the action. The user approves it. The migrated, tested C# code does the work. The model never touches the business rules.
One feature maps closely onto how legacy users already work. Predictive state lets an app render an agent's proposed state change while the model is still generating it, without replacing the committed state. The user then accepts or rejects the proposal. If generation fails, is canceled, or ends without a decision, the provisional value is automatically rolled back.
That's a Save/Cancel form with the assistant filling in the fields. Users who have clicked Cancel on a VB6 dialog ten thousand times won't need training to understand it.
High-volume data entry is the clearest case. An experienced clerk tabbing through a keyboard-driven form will outpace a chat window every time, so leave those screens alone.
The better candidates are tasks that span several screens today: researching an account across four tabs, assembling an exception report, or walking a newer employee through a rarely used process.
.NET 10 is an LTS release supported through November 14, 2028, while .NET 11 is an STS release. Combined with the experimental status of the AI components, the practical plan is:
For a walkthrough of the migration half of this story, see our VELO for VB6 webinar.