You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 8迁移后Blazor WASM本地正常生产环境404问题求助

Blazor WASM从.NET 6迁移至.NET 8后生产环境跳转NotFound问题

我有一个从.NET 6迁移到.NET 8的Blazor WASM客户端应用,本地运行完全正常,但部署到生产环境后会直接跳转到自定义的NotFound页面。已经查了很多资料、试了各种办法,还是没找到问题根源。


项目文件(.csproj)

<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <NeutralLanguage>en</NeutralLanguage>
    <Version>1.11.3</Version>
    <PublishTrimmed>true</PublishTrimmed>
    <TrimMode>link</TrimMode>
    <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
    <PackageReference Include="Google.Apis.Webfonts.v1" Version="1.68.0.3415" />
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.8">
      <TreatAsUsed>true</TreatAsUsed>
    </PackageReference>
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.8" PrivateAssets="all" />
    <PackageReference Include="Microsoft.Authentication.WebAssembly.Msal" Version="8.0.8" />
    <PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
    <PackageReference Include="MudBlazor" Version="7.6.0" />
    <PackageReference Include="System.Text.Json" Version="8.0.4" />
  </ItemGroup>
  
  <ItemGroup>
    <ProjectReference Include="..\SupplierProductRequest.Application\SupplierProductRequest.Application.csproj" />
    <ProjectReference Include="..\SupplierProductRequest.Domain\SupplierProductRequest.Domain.csproj" />
    <ProjectReference Include="..\SupplierProductRequest.Shared\SupplierProductRequest.Shared.csproj" />
    <ProjectReference Include="..\SupplierProductRequest.UI.Shared\SupplierProductRequest.UI.Shared.csproj" />
  </ItemGroup>


  <ItemGroup>
    <Content Update="wwwroot\css\app.css">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
  </ItemGroup>
</Project>

Program.cs代码

WebAssemblyHostBuilder builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.InjectSharedUI();
builder.Services.AddBlazoredLocalStorageAsSingleton();
builder.Services.AddMudBlazorSnackbar();
builder.Services.AddMudBlazorResizeListener();
builder.Services.AddMudBlazorResizeObserver();
builder.Services.AddMudBlazorResizeObserverFactory();
builder.Services.AddMudPopoverService();
builder.Services.AddMudServices();
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddHttpClient<IApiClientService, ApiClientService>(factory: (client) =>
{
    UriBuilder uriBuilder = new(builder.Configuration.GetValue<string>("ApiEndpoint"));
    client.BaseAddress = uriBuilder.Uri;

    string appName = builder.Configuration.GetValue<string?>("ApplicationName") ?? "Online Product Applications";
    string appVersion = Extensions.Version(Assembly.GetExecutingAssembly());

    return new ApiClientService(client, builder.Configuration, appVersion, appName);
});

builder.Services.AddMsalAuthentication<RemoteAuthenticationState, RemoteUserAccount>(options =>
{
    builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
    options.ProviderOptions.DefaultAccessTokenScopes.Add("openid");
    options.ProviderOptions.DefaultAccessTokenScopes.Add("https://graph.microsoft.com/openid");
    options.ProviderOptions.DefaultAccessTokenScopes.Add("offline_access");
    options.ProviderOptions.LoginMode = "redirect";
    options.UserOptions.RoleClaim = "roles";
    options.ProviderOptions.Cache.StoreAuthStateInCookie = true;
});
builder.Services.AddSingleton<AppConfiguration>();

CultureInfo.DefaultThreadCurrentCulture = Constants.DefaultCultureInfo;
CultureInfo.DefaultThreadCurrentUICulture = Constants.DefaultCultureInfo;


await builder.Build().RunAsync();

App.razor代码

<CascadingAuthenticationState>
    <Error>
        <Router AppAssembly="@typeof(App).Assembly">
            <Found Context="routeData">
                <AuthorizeRouteView RouteData="@routeData" DefaultLayout="typeof(InternalAppLayout)">
                    <NotAuthorized>
                        @if (context.User.Identity is null || context.User.Identity.IsAuthenticated == false)
                        {
                            <RedirectToLogin />
                        }
                    </NotAuthorized>
                </AuthorizeRouteView>
                <FocusOnNavigate RouteData="@routeData" Selector="h1" />
            </Found>
            <NotFound>
                <SupplierProductRequest.Admin.Pages.NotFound />
            </NotFound>
        </Router>
    </Error>
        
</CascadingAuthenticationState>

Index.html代码

<title>Online Product Applications</title>
    <base href="/" />
    <link rel="icon" type="image/x-ico href="_content/SupplierProductRequest.UI.Shared/favicon.ico">
    <link href="_content/SupplierProductRequest.UI.Shared/css/custom-loader.css" rel="stylesheet" />
    <link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
    <link href="_content/SupplierProductRequest.UI.Shared/css/font.css" rel="stylesheet" />

    <base />
    <script>

    </script>
    <script src="_framework/blazor.webassembly.js?v=5" async></script>
    <script src="_content/Microsoft.Authentication.WebAssembly.Msal/AuthenticationService.js?v=2" async></script>
    <script src="_content/SupplierProductRequest.UI.Shared/js/shared_ui_methods.js?v=5" defer></script>
    <script src="_content/MudBlazor/MudBlazor.min.js?v=4" defer></script>

</head>
<body style="min-height:600px;">
    <Routes @rendermode="InteractiveServer" />
    <div id="app"></div>
    <!--  <App @rendermode="@RenderMode.WebAssembly" />-->

</body>
</html>

排查与解决方向

  1. 删除Index.html中的重复base标签
    你的Index.html里有两个<base>标签:一个是<base href="/" />,另一个是空的<base />。重复的base标签会干扰Blazor路由解析,直接删除空的那个标签即可。

  2. 配置服务器路由Fallback
    Blazor WASM需要服务器将所有非文件/目录请求转发到index.html,否则刷新或直接访问深层路由会返回404,触发NotFound页面:

    • IIS环境:确保web.config包含重写规则
      <system.webServer>
        <rewrite>
          <rules>
            <rule name="Serve Blazor WASM" stopProcessing="true">
              <match url=".*" />
              <conditions logicalGrouping="MatchAll">
                <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
              </conditions>
              <action type="Rewrite" url="index.html" />
            </rule>
          </rules>
        </rewrite>
      </system.webServer>
      
    • Azure静态Web Apps:在staticwebapp.config.json中配置fallback
      {
        "routes": [
          {
            "route": "/*",
            "serve": "/index.html",
            "statusCode": 200
          }
        ]
      }
      
  3. 修复裁剪模式导致的组件丢失
    项目启用了PublishTrimmed和TrimMode=link,.NET 8的链接裁剪可能会误删未被直接引用的路由组件:

    • 临时关闭PublishTrimmed重新部署验证问题
    • 若需保留裁剪,在Program.cs中显式引用所有路由页面:
      // 显式引用防止被裁剪
      _ = typeof(SupplierProductRequest.Admin.Pages.Home);
      _ = typeof(SupplierProductRequest.Admin.Pages.YourOtherPage);
      
  4. 移除冲突的RenderMode配置
    Index.html中的<Routes @rendermode="InteractiveServer" />和注释的WebAssembly根组件冲突,直接删除这个<Routes>标签,确保根组件由Program.cs中的builder.RootComponents.Add<App>("#app");加载。

  5. 检查生产环境认证配置
    确认生产环境appsettings.json中的Azure AD回调URL与生产域名匹配,打开浏览器控制台查看是否有认证相关的错误日志,认证异常可能间接导致路由跳转异常。

内容的提问来源于stack exchange,提问作者Thompho Setjie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 18:09:52