Search code examples
c#angularasp.net-coreasp.net-core-identity

Why will the AspNetCore Identity scaffolding not load its associated CSS and JS files when my app uses a different appsettings file?


I wanted to add a "Local" appsettings file (called "appsettings.Local.json") that would contain information for debugging my AspNetCore/Angular app (created from the default VS2019 template) on an individual/local computer. However, when I set my ASPNETCORE_ENVIRONMENT variable in the Project's properties to "Local", I get a bunch of errors in the Chrome console regarding the CSS and JS files not loading when I attempt loading the scaffolded Login screen.

enter image description here

enter image description here

What makes zero sense whatsoever, is when I change the ASPNETCORE_ENVIRONMENT variable from "Local" back to "Development", these errors go away and the Login screen renders correctly.

enter image description here

It may be worth noting that my Startup.cs file looks like this (switched out env.IsDevelopment() to env.IsEnvironment("Local"); but regardless of what I use here, there's no noticeable change in the rendering of the Login screen).

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsEnvironment("Local"))
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            // 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.UseLoggingMiddleware(Configuration["TABLE_STORAGE_KEY"], Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"));

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        if (!env.IsEnvironment("Local"))
        {
            app.UseSpaStaticFiles();
        }

        app.UseRouting();

        app.UseAuthentication();
        app.UseIdentityServer();
        app.UseAuthorization();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller}/{action=Index}/{id?}");
            endpoints.MapRazorPages();
        });

        app.UseSpa(spa =>
        {
            // To learn more about options for serving an Angular SPA from ASP.NET Core,
            // see https://go.microsoft.com/fwlink/?linkid=864501

            spa.Options.SourcePath = "ClientApp";

            if (env.IsEnvironment("Local"))
            {
                //spa.UseAngularCliServer(npmScript: "start");
                spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
            }
        });
    }

Possibly related: I did also recently upgrade from .NET Core 3.1 to .NET 5, but I haven't been able to find anything online about this being a cause of my issue.

EDIT: 5/12/2021 01: It appears that the JS and CSS files in question aren't getting copied to the output directory when ASPNETCORE_ENVIRONMENT is set to "Local", because I can't navigate to https://localhost:44395/Identity/lib/bootstrap/dist/js/bootstrap.bundle.min.js unless the ASPNETCORE_ENVIRONMENT is set to "Development". But why would this be occurring?


Solution

  • The ASP.NET Core Identity UI uses Static Web Assets, which I explain in detail in this answer. Essentially, this maps URLs for /Identity/ to file-paths rooted at something like the following:

    /path/to/.nuget/packages/microsoft.aspnetcore.identity.ui/*.*.*/staticwebassets/V4
    

    As noted in the linked question and answer, this only occurs out of the box in the Development environment. In your scenario, you require this for the Local environment, which you can configure, for example, in Program.cs (assuming a typical setup), like this:

    webBuilder.UseStartup<Startup>(); // This line is shown just for context.
    
    // ...
    
    webBuilder.ConfigureAppConfiguration((ctx, _) =>
    {
        if (ctx.HostingEnvironment.IsEnvironment("Local"))
        {
            StaticWebAssetsLoader.UseStaticWebAssets(
                ctx.HostingEnvironment, ctx.Configuration);
        }
    });
    

    This ensures that the Static Web Assets mapping runs also for the Local environment.