'Blazor WebAssembly Hosted on IIS - only API is working

I have a project where I have developed a solution with Blazor WebAssembly Hosted model. I have a Server Project, a Client project and a Shared project (but I renamed it to Domain).

When I publish, I publish to a folder because I have no other ways of connecting to the server I try to deploy to, which is of Windows Server 2019 OS.

Then I add the published folder to IIS but I can only get the API endpoints working. When I navigate to the root of the application, i.e. https:/localhost:5001 I just get a 404 error.

I have installed dependencies for .NET, URL Rewrite, added a self-signed certificate etc.

I can't understand why this doesn't work. When I launch in Visual Studio it works perfectly fine both with Release and Debug flags.

Can someone guide me to what I might have done wrong?

Log when navigating to https://localhost:5001 (not working)

[10:11:24 Information] Microsoft.Hosting.Lifetime Application started. Press Ctrl+C to shut down.

[10:11:24 Information] Microsoft.Hosting.Lifetime Hosting environment: Production

[10:11:24 Information] Microsoft.Hosting.Lifetime Content root path: C:\Temp\Project\publish

[10:11:24 Information] Microsoft.AspNetCore.Hosting.Diagnostics Request starting HTTP/2 GET https://localhost:5001/ - -

[10:11:25 Information] Microsoft.AspNetCore.Routing.EndpointMiddleware Executing endpoint 'Fallback {*path:nonfile}'

[10:11:25 Information] Microsoft.AspNetCore.Routing.EndpointMiddleware Executed endpoint 'Fallback {*path:nonfile}'

[10:11:25 Information] Microsoft.AspNetCore.Hosting.Diagnostics Request finished HTTP/2 GET https://localhost:5001/ - - - 404 - - 94.7963ms

Log when navigating to https://localhost:5001/api/dataflows (works)

[10:12:46 Information] Microsoft.AspNetCore.Hosting.Diagnostics Request starting HTTP/2 GET https://localhost:5001/api/dataflows - -

[10:12:47 Information] Microsoft.AspNetCore.Routing.EndpointMiddleware Executed endpoint 'Project.Web.Server.Controllers.DataflowsController.GetDataflows (Project.Web.Server)'

[10:12:47 Information] Microsoft.AspNetCore.Hosting.Diagnostics Request finished HTTP/2 GET https://localhost:5001/api/dataflows - - - 200 2 application/json;+charset=utf-8 619.7714ms

Project.Web.Server/Statup.cs: ConfigureServices

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseMigrationsEndPoint();
        app.UseWebAssemblyDebugging();
    }
    else
    {
        app.UseExceptionHandler("/Error");
    }

    app.UseBlazorFrameworkFiles();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseIdentityServer();
    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapControllers();
        endpoints.MapFallbackToFile("{*path:nonfile}", "index.html"); ;
    });
}

Project.Web.Server/appsettings.json

{
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "Identity": "Data Source=|DataDirectory|\\IdentityDB.db",
    "Api": "Data Source=|DataDirectory|\\ApiDB.db",
    "Dataflows": "Data Source=|DataDirectory|\\DataflowsDB.db"
  },
  "IdentityServer": {
    "Clients": {
      "Project.Web.Client": {
        "Profile": "IdentityServerSPA"
      }
    },
    "Key": {
      "Type": "Store",
      "StoreName": "My",
      "StoreLocation": "CurrentUser",
      "Name": "CN=localhost"
    }
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information",
      "Microsoft.EntityFrameworkCore.Database.Command": "Warning"
    }
  },
  "Serilog": {
    "Using": [ "Serilog.Sinks.File" ],
    "WriteTo": [
      {
        "Name": "File",
        "Args": {
          "path": "C:\\Temp\\Project\\log.txt",
          "outputTemplate": "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}"
        }
      }
    ],
    "Enrich": [ "FromLogContext", "WithExceptionDetails" ]
  }
}

Project.Web.Client/Program.cs: ConfigureServices

public static Task Main(string[] args)
{
    var builder = WebAssemblyHostBuilder.CreateDefault(args);
    builder.RootComponents.Add<App>("#app");

    builder.Services.AddHttpClient("Project.Web.Client.API", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
       .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

    // Supply HttpClient instances that include access tokens when making requests to the server project
    builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("Project.Web.Client.API"));

    // Add Open ID Connect client settings
    builder.Services.AddOidcAuthentication(options =>
    {
        builder.Configuration.Bind("oidc", options.ProviderOptions);
    }).AddAccountClaimsPrincipalFactory<RolesClaimsPrincipalFactory>();

    builder.Services.AddOptions();
    builder.Services.AddAuthorizationCore();
    builder.Services.AddApiAuthorization();
    return builder.Build().RunAsync();
}

Project.Web.Client/Shared/RedirectToLogin.razor

@inject NavigationManager Navigation
@code {
    protected override void OnInitialized()
    {
        Navigation.NavigateTo($"authentication/login?returnUrl={Uri.EscapeDataString(Navigation.Uri)}");
    }
}

Project.Web.Client/wwwroot/index.html

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>Project.Web</title>
    <base href="/" />
    <link href="/company/fonts/css/styles-technical.css" rel="stylesheet" />
    <link href="/company/icons/css/styles.css" rel="stylesheet" />

</head>

<body>
    <div id="app">Loading...</div>

    <script src="_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js"></script>
    <script src="_framework/blazor.webassembly.js"></script>
    <script type="module">
        import { defineCustomElements } from '/company/web-ui/loader/index.js';
        defineCustomElements(window);
    </script>
    <script src="/scripts/utils.js"></script>
</body>

</html>

Project.Web.Client/wwwroot/appsettings.json

{
  "oidc": {
    "Authority": "https://localhost:5001/",
    "ClientId": "Project.Web.Client",
    "ResponseType": "code",
    "DefaultScopes": [
      "openid",
      "profile"
    ],
    "PostLogoutRedirectUri": "/",
    "RedirectUri": "https://localhost:5001/authentication/login-callback"
  }
}


Solution 1:[1]

Make sure you install the .Net core hosting bundle on your server.

https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-aspnetcore-6.0.3-windows-hosting-bundle-installer

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 tellyman