How to properly set a launch URL that is hosted using IIS? (Documentation)

How to properly set a launch URL that is hosted using IIS? (Documentation)
typescript
Ethan Jackson

I can launch to my preferred URL of the Razor page I desire, but this works only in DEVELOPMENT mode or in debug mode. However, when deploying my Blazor web app on Windows Server 2012 R2 Standard using IIS 8.5, the automatic URL launching functionality is not present, which is a key difference between debug and deployment.

I found out that the configuration in launchSettings.json file, more specifically, the launchUrl settings, is applicable only in debug mode.

{ "$schema": "https://json.schemastore.org/launchsettings.json", "profiles": { "http": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, "hotReloadEnabled": true, "launchUrl": "account/login", "applicationUrl": "http://localhost:5113", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "https": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, "hotReloadEnabled": true, "launchUrl": "account/login", "applicationUrl": "https://localhost:7233;http://localhost:5113", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } }

So I tried to refactor the App.razor because of my findings about the launchSettings.json configurations.

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <base href="/account/login" /> <link rel="stylesheet" href="@Assets["lib/bootstrap/dist/css/bootstrap.min.css"]" /> <link rel="stylesheet" href="@Assets["app.css"]" /> <link rel="stylesheet" href="@Assets["MyProject.styles.css"]" /> <ImportMap /> <link rel="icon" type="image/png" href="favicon.png" /> <HeadOutlet /> </head> <body> <Routes /> <script src="_framework/blazor.web.js"></script> <script src="lib/bootstrap/dist/js/bootstrap.min.js"></script> </body> </html>

Well, this works, but not in an expected outcome. I mean, the resources such as the client-side scripts are missing. Therefore, I considered this configuration as incorrectly configured. Please note that I'm not using IIS sub-application hosting on my end.

In additional, here's my Program.cs configurations:

using MyProject.Components; using Microsoft.EntityFrameworkCore; using MyProject.Data.SQLite; using MyProject.Data.SQLServer; using MyProject.Components.Account; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Identity; using MyProject.Data.SQLiteAuth; var builder = WebApplication.CreateBuilder(args); builder.Services.AddDbContextFactory<SQLServerContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("SQLServerContext") ?? throw new InvalidOperationException("Connection string 'SQLServerContext' not found."))); builder.Services.AddDbContextFactory<SqliteAuthContext>(options => options.UseSqlite(builder.Configuration.GetConnectionString("SqliteAuthContext") ?? throw new InvalidOperationException("Connection string 'SqliteAuthContext' not found."))); builder.Services.AddQuickGridEntityFrameworkAdapter(); builder.Services.AddDatabaseDeveloperPageExceptionFilter(); // Add services to the container. builder.Services.AddRazorComponents() .AddInteractiveServerComponents() .AddInteractiveWebAssemblyComponents(); builder.Services.AddCascadingAuthenticationState(); builder.Services.AddScoped<IdentityUserAccessor>(); builder.Services.AddScoped<IdentityRedirectManager>(); builder.Services.AddScoped<AuthenticationStateProvider, IdentityRevalidatingAuthenticationStateProvider>(); builder.Services.AddAuthentication(options => { options.DefaultScheme = IdentityConstants.ApplicationScheme; options.DefaultSignInScheme = IdentityConstants.ExternalScheme; }) .AddIdentityCookies(); builder.Services.AddIdentityCore<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<BlazorAuthContext>() .AddSignInManager() .AddDefaultTokenProviders(); builder.Services.AddSingleton<IEmailSender<IdentityUser>, IdentityNoOpEmailSender>(); var app = builder.Build(); // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error", createScopeForErrors: true); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); app.UseMigrationsEndPoint(); } app.UseHttpsRedirection(); app.UseAntiforgery(); app.MapStaticAssets(); app.MapRazorComponents<App>() .AddInteractiveServerRenderMode() .AddInteractiveWebAssemblyRenderMode(); app.MapAdditionalIdentityEndpoints(); app.Run();

Moreover, if I refactor <base href="/account/login" /> into <base href="/" />, I am not getting the launch URL I wanted (account/login), it throws this status instead,

This localhost page can’t be found
HTTP ERROR 404

To be more specific, I want to launch the URL {domain}:{port}/account/login by default upon clicking the site directly from IIS Manager:

launch-web-app

Unfortunately, I couldn't get what I wanted.

Answer

This solution is just a workaround that does not guarantee that it is appropriate in the official production phase. However, the good thing about this workaround is that it is working as expected, achieving what I wanted to achieve.

The App.razor should use the default configuration of <base> tag through this setting:

<base href="/" />

Lastly, in Program.cs, add these configurations, for example, above the app.Run();:

app.Use(async (context, next) => { if (context.Request.Path == "/") { context.Response.Redirect("/account/login"); return; } await next(); }); app.Run();

This will resolve the error status:

This localhost page can’t be found
HTTP ERROR 404

And also, redirect me to the URL path I desire without any issues (so far).

Related Articles