On the first page load in a browser session, the app works fine — InteractiveAuto picks Server (SignalR circuit) rendering since WebAssembly isn't cached yet. On any subsequent load in the same session (a plain F5 refresh, or logging into a different tenant without a full page reload), InteractiveAuto switches to WebAssembly, and the WASM host throws during boot:
Error: AggregateException_ctor_DefaultMessage (Method not found: object Autofac.Core.KeyedService.get_AnyKey()) at callEntryPoint (blazor.web.js) Note there is no corresponding server-side log entry for this exception — it never reaches the server, confirming it originates entirely inside the WASM sandbox during Volo.Abp.Autofac.WebAssembly's container build.
Root cause (as far as we traced it)
The app's Nexus.HttpApi.Client module calls AddHttpClientProxies(...), ABP's dynamic (Castle DynamicProxy-based) C# client proxy generator. Castle DynamicProxy depends on System.Reflection.Emit to generate proxy types at runtime, which is unsupported in Blazor WebAssembly's Mono interpreter (confirmed via castleproject/Core#585). We regenerated these as static proxies via abp generate-proxy -t csharp --without-contracts, which resolved that specific MissingMethodException — confirming the diagnosis.
However, Volo.Abp.Autofac.WebAssembly itself still makes Autofac the WASM app's underlying DI container (via options.UseAutofac() in Program.cs), and anything else Autofac chooses to intercept hits the same wall — after fixing the HTTP client proxies, the identical MissingMethodException on KeyedService.AnyKey recurred for a different type, with a stack trace showing Castle's internal type-inspection calls (RuntimeType.GetAttributeFlagsImpl, Type.get_IsInterface, RuntimeType.GetBaseType, etc.).
Attempting the "recommended" fix (remove Autofac from the WASM client) surfaces a second bug
Per your own guidance elsewhere (e.g. the MAUI Autofac removal discussion), we removed AbpAutofacWebAssemblyModule from the client module's [DependsOn], removed the Volo.Abp.Autofac.WebAssembly package reference, and removed options.UseAutofac() from Program.cs, falling back to the default Microsoft.Extensions.DependencyInjection container.
This surfaced a different crash immediately — a captive-dependency validation failure (ScopedInSingletonException for IStringLocalizerFactory, IAuthorizationHandler, etc. injected into ApplicationConfigurationChangedService), which we resolved by explicitly disabling ValidateScopes/ValidateOnBuild on WebAssemblyHostBuilder (matching what the default WASM host already does automatically outside Development).
Past that, we hit a third, deeper failure inside your own framework bootstrap:
Error: AggregateException_ctor_DefaultMessage (An error occurred during the initialize Volo.Abp.Modularity.OnApplicationInitializationModuleLifecycleContributor phase of the module Volo.Abp.AspNetCore.Components.WebAssembly.AbpAspNetCoreComponentsWebAssemblyModule, Volo.Abp.AspNetCore.Components.WebAssembly, Version=10.4.0.0: Arg_NullReferenceException. See the inner exception for details.) We traced this (via decompilation) to AbpAspNetCoreComponentsWebAssemblyModule.OnApplicationInitializationAsync, specifically this line:
await context.ServiceProvider.GetRequiredService<IClientScopeServiceProviderAccessor>() .ServiceProvider.GetRequiredService<WebAssemblyCachedApplicationConfigurationClient>() .InitializeAsync()... IClientScopeServiceProviderAccessor.ServiceProvider is supposed to be set in AbpWebAssemblyHostBuilderExtensions.InitializeApplicationAsync just before this runs, via a hard cast to ComponentsClientScopeServiceProviderAccessor. We could not conclusively determine, from static decompilation alone, why this ends up null once Autofac is no longer the container — it's possible this depends on Autofac-specific scope/lifetime behavior that the default provider doesn't replicate the same way in this exact bootstrap sequence.
Is Volo.Abp.Autofac.WebAssembly known to be incompatible with Autofac's keyed-service support (Autofac.Extensions.DependencyInjection 11.0.0 / native KeyedService.AnyKey) specifically inside the Blazor WASM Mono runtime? Is there a supported combination of versions where this works? If the intended fix is to not use Autofac in the WASM client at all, what's the correct way to keep IClientScopeServiceProviderAccessor/WebAssemblyCachedApplicationConfigurationClient initialization working without it? Is there a missing registration or setup step on our end? Is there a recommended/supported way to keep InteractiveAuto while avoiding both of these failure modes, short of dropping to InteractiveServer entirely?
3 Answer(s)
-
0
Hi,
First, the setup itself is fine. Autofac + dynamic HTTP client proxies + InteractiveAuto is exactly what the ABP 10.4 Blazor Web App template ships in the
.Clientproject, so you didn't misconfigure anything there. I'd revert the Autofac removal (putAbpAutofacWebAssemblyModuleback in[DependsOn], restore theVolo.Abp.Autofac.WebAssemblypackage andoptions.UseAutofac(), and drop theValidateScopes/ValidateOnBuildchange). Removing Autofac is what pushed you into the captive-dependency error and then the nullIClientScopeServiceProviderAccessor, and it isn't a supported swap for this template — disabling scope validation only hides the captive dependency, it doesn't fix the lifetimes.About the main error:
Method not found: Autofac.Core.KeyedService.get_AnyKey()is worth reading carefully. That member exists in every Autofac version in play here (9.1.0 withAutofac.Extensions.DependencyInjection11.0.0), and it isn't removed by trimming. A "method not found" on a member that's actually present almost always means theAutofac.dllthe browser is running doesn't match theAutofac.Extensions.DependencyInjection.dllthat calls it — i.e. the WASM assets the browser loaded came from more than one build (stale browser/service-worker cache, a CDN edge, or a non-atomic deploy), rather than a real Autofac-vs-WASM incompatibility.The "first load is fine, every later load fails, and a plain F5 triggers it" pattern fits that: the first request renders on the server (fresh, server-side assemblies), and the later loads run the cached WASM bundle in the browser.
So I'd start here:
- Restore the default Autofac config above.
- Do a clean, atomic redeploy of the client and load it in a fresh browser profile (hard reload; if you shipped the PWA/service worker, bump or clear it). The goal is to make sure every
_frameworkasset the browser fetches comes from the same build. - While testing, publish the client per our deployment docs with
dotnet publish -c Release -p:PublishTrimmed=false(and noRunAOTCompilation). That's the documented baseline for the Blazor project and takes the linker/AOT out of the picture as a variable.
If it still reproduces on a clean, cache-free deploy, send these over and we'll take it from there:
- The full exception including all inner exceptions (not just the outer line).
dotnet list <YourProject>.Blazor.WebApp.Client package --include-transitiveanddotnet --info.- Your exact publish command plus any
Directory.Build.*/.pubxml, and the effective values ofPublishTrimmed,TrimMode,RunAOTCompilation. - The
Autofac.dll/Autofac.Extensions.DependencyInjection.dllversions actually sitting in the deployed_frameworkfolder. - Your full
Program.cs(both the Autofac and no-Autofac versions).
If any of that is large, you can email it to liming.ma@volosoft.com, or share a minimal project that reproduces it on a fresh 10.4 template.
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Thanks for the pointer — reverting the Autofac removal and stepping back from the DynamicProxy trail was the right call.
The actual root cause: our WASM client's wwwroot/appsettings.json had RemoteServices:Default:BaseUrl hardcoded to one specific address. Our server is reachable on two different addresses (a private IP for internal testers, a public IP for external ones), so that fixed value only ever matched one of them. Loading the app from the other address made the WASM client issue a genuine cross-origin request to the wrong origin, which the browser blocked — surfacing as a Cross-Origin Request Blocked error on /api/abp/application-configuration. That's almost certainly what was producing the confusing, inconsistent errors we were chasing (works once, breaks on refresh, breaks on tenant switch), since we were testing across both addresses without realizing the client was pinned to just one of them.
Fix: in the client's module ConfigureServices, we now set AbpRemoteServiceOptions.RemoteServices.Default.BaseUrl at runtime from IWebAssemblyHostEnvironment.BaseAddress, so the client always calls whichever origin it was actually loaded from, instead of a fixed value.
With that in place: reverted to stock Autofac config in the WASM client, restored InteractiveAuto, and confirmed clean with PublishTrimmed back to its default (on) after a clean atomic publish — F5 refresh and switching tenants both work correctly now, from both addresses.
So no framework incompatibility on your end — appreciate you steering us away from a much deeper (and wrong) rabbit hole. Closing this out.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Glad you tracked it down, and thanks for posting the root cause — it's a useful one. Setting
RemoteServices.Default.BaseUrlfromIWebAssemblyHostEnvironment.BaseAddressat runtime is exactly the right move when the same app is served from more than one origin; a fixed BaseUrl in appsettings.json always pins the client to a single origin and breaks cross-origin from the others.Good to hear the stock Autofac + InteractiveAuto setup runs clean with trimming back on. Feel free to reopen if anything else comes up.
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)