Summary
The issue occurs because the DisableScopedCssBundling property effectively bypasses the automatic Static Web Asset bundling pipeline. When applied to a .NET MAUI Blazor Hybrid and Web App multiproject (specifically within the Shared project), the build system stops generating the virtual _content/{AssemblyName}.styles.css file that the host projects expect to load.
Furthermore, the user is utilizing a global app.css file accessed via the _content virtual path. Standard CSS isolation is required to resolve the _content path for Shared projects in MAUI Blazor. Disabling it breaks the asset resolution mechanism without replacing it with a manual resolution strategy.
Root Cause
The root cause is a misunderstanding of the Static Web Assets Manifest resolution chain in a multi-targeted MAUI solution.
- Static Web Assets (SWA) Manifest: The Shared project (Class Library) compiles CSS files into
objfolders. The build process generates astaticwebassets.manifest.jsonthat maps virtual paths (like_content/MyApp.Shared/app.css) to physical files. - Scoped CSS Bundling: The
DisableScopedCssBundlingproperty tells the SDK: “Stop automatically generating the bundled.styles.cssfile and don’t automatically wire it up.” This is intended for custom build pipelines. - The MAUI Web Context: In the Web project (Razor Components), the
<link>tag requires the SWA runtime to resolve_content/Question260197-1.Shared/app.css. This resolution relies on the SWA manifest being active. - The Failure:
- When you add
<DisableScopedCssBundling>true</DisableScopedCssBundling>to the Shared project, you break the generation of the manifest entries required for the host projects to find the files. - The build error “No file exists for the asset” happens because the build targets try to bundle the isolated CSS (even though you disabled the bundling wrapper) but fail to find the generated files in the specific platform
objfolders (e.g.,net10.0-maccatalyst). - The runtime error
ERR_ADDRESS_UNREACHABLE(or 404) for/Question260197-1.styles.csshappens because the Web project still attempts to load a scoped bundle that you have told the build system not to create.
- When you add
Why This Happens in Real Systems
- Abstraction Leaks: The MAUI Blazor Hybrid + Web template tries to share code via a Razor Class Library (RCL). RCLs rely heavily on the Static Web Assets system to serve CSS/JS to consuming apps. Developers often try to “turn off” features (like CSS Scoping) to simplify their CSS architecture, not realizing those features are actually the glue holding the virtual file system together.
- Global Styles vs. Scoped Styles: Developers often want global styles (no BEM, no scoping) but use the RCL structure which defaults to scoped/consumable assets. The conflict arises when they disable the mechanism that serves those assets.
Real-World Impact
- Build Failures: The build pipeline throws
System.InvalidOperationExceptionbecause it cannot reconcile the asset definitions with the physical files on disk. - Runtime 404s: The application starts, but styles fail to load, resulting in unstyled UI.
- Development Deadlock: The “standard” fix (disabling isolation) breaks the project, and the default behavior (enabling isolation) forces unwanted CSS scoping syntax (
b-{hash}) on global styles.
Example or Code
If you are trying to share a global app.css without scoping, you should not disable the bundling mechanism. Instead, configure the static web assets to treat the CSS as a raw resource, but keep the discovery mechanism active.
However, if you must disable scoping (e.g., for legacy CSS reasons), you cannot rely on the _content virtual path for Shared assets in MAUI Web projects without manual intervention.
Correct Project Configuration (Standard Approach):
false
Code to Reference Shared CSS (in App.razor or index.html):
How Senior Engineers Fix It
Senior engineers address this by aligning the build configuration with the asset delivery requirement. Since the _content path relies on the Static Web Asset infrastructure, you cannot disable the infrastructure entirely.
-
Re-enable Scoped CSS Bundling: Set
DisableScopedCssBundlingtofalse(or remove the property) in the Shared project. -
Target Global CSS: Instead of disabling the mechanism, target the specific file. Ensure the CSS file is in the
wwwrootfolder of the Shared project. -
Avoid the Build Error: If the build error regarding
Question260197-1.styles.csspersists (the MAUI host project trying to load a bundle), you must suppress the generation of the bundle only on the Shared project but ensure the assets are still published.- Actually, the correct fix is to ensure the Shared project does not try to bundle its own CSS as a “site” but rather as a library.
The Senior Fix:
Remove<DisableScopedCssBundling>true</DisableScopedCssBundling>from the Shared project. It is not needed there.
If you want to avoid scoping classes (e.g.,b-xyz), put your styles in a file outside theApp.razorscope or use::deepor simply write your CSS selectors to be specific enough. The “non-scoped” requirement is best met by not putting the CSS inside the<style>block of a component, but keeping it inwwwroot/app.css.If you truly want to bypass the
_contentrouting, the “Senior” architectural move is to move theapp.cssinto the Web Projectwwwrootor the MAUI Projectwwwrootand reference it relatively, abandoning the “Shared Project CSS via Virtual Path” pattern entirely, as it is brittle across different MAUI targets.
Why Juniors Miss It
- Property Misplacement: Juniors often put project properties (like
DisableScopedCssBundling) in the wrong.csprojfile. It belongs in the consuming project (the Web or MAUI project) to control how that project bundles assets, not in the Shared library which supplies the assets. - Confusing “Scope” with “Location”: Juniors think “Disabling Scoped CSS” means “Stop putting
b-xyzhashes in my class names.” It actually means “Stop managing the lifecycle of the CSS file entirely.” They don’t realize the virtual path_content/is a service provided by that lifecycle management. - Ignoring Platform Paths: The error message mentions
maccatalyst-x64andiossimulator-x64. Juniors often miss that MAUI is multi-targeted. A setting in a Shared project might break the build for one specific target platform (iOS) while working on another (Web), leading to inconsistent build results.