'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.
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 |