Buconos

Upgrading Copilot Studio to .NET 10 WebAssembly: A Step-by-Step Guide

Published: 2026-05-18 10:27:10 | Category: Web Development

Introduction

If you're running Copilot Studio on .NET 8 WebAssembly, moving to .NET 10 can unlock significant performance improvements and simplify your build pipeline. This guide walks you through the exact process that the Copilot Studio team used to upgrade their .NET WASM engine. You'll learn how to update your project, remove manual asset-fingerprinting scripts, take advantage of automatic AOT stripping, and even optimize a dual-engine (JIT + AOT) packaging strategy. By the end, you'll have a faster, leaner web application that runs C# directly in the browser.

Upgrading Copilot Studio to .NET 10 WebAssembly: A Step-by-Step Guide
Source: devblogs.microsoft.com

What You Need

  • Existing .NET 8 WebAssembly project (Blazor WASM or similar)
  • .NET 10 SDK installed (download from dotnet.microsoft.com)
  • Your project's .csproj files
  • A list of all NuGet dependencies
  • If using custom fingerprinting: a copy of your PowerShell script (if any) and the blazor.boot.json manifest
  • A CI/CD pipeline that publishes the WebAssembly app
  • Optional: an NPM package if you distribute dual engines

Step-by-Step Guide

Step 1: Update Your Target Framework

Open every .csproj file in your solution and change the TargetFramework from net8.0 to net10.0. For example:

<TargetFramework>net10.0</TargetFramework>

Save all files. This is the primary change – the .NET 10 SDK will automatically use the new WebAssembly runtime and tooling.

Step 2: Verify Dependency Compatibility

Run dotnet restore and look for any NuGet packages that are not compatible with .NET 10. Update packages that have newer versions targeting .NET 10. For Copilot Studio, the team found that most packages worked without issues, but you should check each one. If a package doesn't have a .NET 10 build, see if the .NET 8 build still works – often it does, but test carefully.

Step 3: Remove Custom Asset Fingerprinting

In .NET 10, automatic fingerprinting of WASM assets is built in. That means you can delete any custom scripts you used for this purpose. Specifically:

  • Remove your custom PowerShell (or other) script that renamed files with SHA256 hashes.
  • Remove the integrity argument from your JavaScript resource loader when fetching dotnet.js or other WASM assets.
  • Delete any configuration that reads blazor.boot.json to enumerate assets for fingerprinting – the new build process handles this automatically.

Now, when you publish, each asset's filename will include a unique fingerprint. Cache-busting and integrity validation happen out of the box. Your existing caching logic will still work because the fingerprinted URLs are new.

Step 4: Enable AOT with Default Stripping

.NET 10 sets WasmStripILAfterAOT to true by default for AOT builds. This means after ahead-of-time compiling your .NET code to WebAssembly, the original Intermediate Language (IL) is removed from the published output, reducing download size. If you were using AOT in .NET 8, you may have had to explicitly set this property. Now you can simply ensure your project file includes <RunAOTCompilation>true</RunAOTCompilation>. The stripping happens automatically.

If you use a dual-engine strategy (JIT + AOT, as Copilot Studio does), note that stripped AOT assemblies will no longer be bit-for-bit identical with their JIT counterparts. This prevents file deduplication between the two modes. To handle this, proceed to Step 5.

Upgrading Copilot Studio to .NET 10 WebAssembly: A Step-by-Step Guide
Source: devblogs.microsoft.com

Step 5: Optimize Dual Engine Packaging (Optional)

Copilot Studio ships a single NPM package containing both a JIT engine (for fast startup) and an AOT engine (for maximum execution speed). At runtime, they load in parallel: the JIT engine handles initial interactions while the AOT engine compiles, then control hands off. Because WasmStripILAfterAOT makes AOT assemblies different from JIT ones, you can no longer deduplicate identical files. To keep your package size manageable:

  • Review which assets are shared between the two engines (e.g., .NET runtime files, configuration). Keep only those common assets in a shared folder.
  • For engine-specific files, place them in separate folders (jit/ and aot/).
  • Use a build script to copy the appropriate assets into your NPM package after publishing both configurations.

This approach still gives you the best of both worlds without excessive duplication.

Step 6: Deploy and Validate

Publish your app using dotnet publish -c Release. Deploy the output to your hosting environment (e.g., Azure Static Web Apps, CDN). Test thoroughly:

  • Check that all assets load with correct fingerprints (no 404s).
  • Verify integrity validation – .NET 10 will automatically reject tampered files.
  • Measure startup time and runtime performance. Expect improvements from the newer runtime and AOT stripping.
  • If using dual engines, confirm that the handoff from JIT to AOT works smoothly.

Tips

  • WebWorker initialization: If you load the .NET WASM runtime inside a WebWorker, set dotnetSidecar = true when calling dotnet.init() to ensure proper initialization in a worker context.
  • Test on production-like environment: Because fingerprinting changes resource URLs, make sure your CDN caching rules and service workers handle the new filenames correctly.
  • Monitor bundle size: After stripping IL, your AOT download may shrink significantly. Compare before and after using browser DevTools.
  • Keep an eye on dependencies: Some libraries may have subtle behavioral changes between .NET 8 and .NET 10. Run your full test suite.
  • Rollback plan: Maintain the ability to revert to .NET 8 quickly by keeping your old .csproj and scripts in source control.