Base solution for your next web application
Open Closed

InlIne Middleware not redirecting 404 to index.html #9871


User avatar
0
GarethWright created

.net core Angular Single Project 9.0.1

This works fine locally but when publishing to IIS any deep link i.e /account/login returns a 404.

It should all as the provided

app.Use(async (context, next) => { await next(); if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value)) { context.Request.Path = "/index.html"; await next(); 
            
            } });

should handle those 404s

namespace PROJECT.Web.Startup { public class Startup { private const string DefaultCorsPolicyName = "localhost";

    private readonly IConfigurationRoot _appConfiguration;
    private readonly IWebHostEnvironment _hostingEnvironment;

    public Startup(IWebHostEnvironment env)
    {
        _hostingEnvironment = env;
        _appConfiguration = env.GetAppConfiguration();
    }

    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        //MVC
        services.AddControllersWithViews(options =>
        {
            options.Filters.Add(new AbpAutoValidateAntiforgeryTokenAttribute());
        }).AddNewtonsoftJson();

        services.AddSignalR();

        //Configure CORS for angular2 UI
        services.AddCors(options =>
        {
            options.AddPolicy(DefaultCorsPolicyName, builder =>
            {
                //App:CorsOrigins in appsettings.json can contain more than one address with splitted by comma.
                builder
                    .WithOrigins(
                        // App:CorsOrigins in appsettings.json can contain more than one address separated by comma.
                        _appConfiguration["App:CorsOrigins"]
                            .Split(",", StringSplitOptions.RemoveEmptyEntries)
                            .Select(o => o.RemovePostFix("/"))
                            .ToArray()
                    )
                    .SetIsOriginAllowedToAllowWildcardSubdomains()
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials();
            });
        });

        if (bool.Parse(_appConfiguration["KestrelServer:IsEnabled"]))
        {
            ConfigureKestrel(services);
        }

        IdentityRegistrar.Register(services);
        AuthConfigurer.Configure(services, _appConfiguration);

        //Identity server
        if (bool.Parse(_appConfiguration["IdentityServer:IsEnabled"]))
        {
            IdentityServerRegistrar.Register(services, _appConfiguration, options =>
                 options.UserInteraction = new UserInteractionOptions()
                 {
                     LoginUrl = "/UI/Login",
                     LogoutUrl = "/UI/LogOut",
                     ErrorUrl = "/Error"
                 });
        }

        if (WebConsts.SwaggerUiEnabled)
        {
            //Swagger - Enable this line and the related lines in Configure method to enable swagger UI
            services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo() { Title = "inteliProCS API", Version = "v1" });
                options.DocInclusionPredicate((docName, description) => true);
                options.ParameterFilter<SwaggerEnumParameterFilter>();
                options.SchemaFilter<SwaggerEnumSchemaFilter>();
                options.OperationFilter<SwaggerOperationIdFilter>();
                options.OperationFilter<SwaggerOperationFilter>();
                options.CustomDefaultSchemaIdSelector();
            }).AddSwaggerGenNewtonsoftSupport();
        }

        //Recaptcha
        services.AddreCAPTCHAV3(x =>
        {
            x.SiteKey = _appConfiguration["Recaptcha:SiteKey"];
            x.SiteSecret = _appConfiguration["Recaptcha:SecretKey"];
        });

        if (WebConsts.HangfireDashboardEnabled)
        {

            //Hangfire(Enable to use Hangfire instead of default job manager)
            services.AddHangfire(config =>
            {
                config.UseSqlServerStorage(_appConfiguration.GetConnectionString("Default"));

            });
        }

        if (WebConsts.GraphQL.Enabled)
        {
            services.AddAndConfigureGraphQL();
        }

        if (bool.Parse(_appConfiguration["HealthChecks:HealthChecksEnabled"]))
        {
            services.AddAbpZeroHealthCheck();

            var healthCheckUISection = _appConfiguration.GetSection("HealthChecks")?.GetSection("HealthChecksUI");

            if (bool.Parse(healthCheckUISection["HealthChecksUIEnabled"]))
            {
                services.Configure<HealthChecksUISettings>(settings =>
                {
                    healthCheckUISection.Bind(settings, c => c.BindNonPublicProperties = true);
                });
                services.AddHealthChecksUI();
            }
        }

        //Configure Abp and Dependency Injection
        return services.AddAbp<inteliProCSWebHostModule>(options =>
        {
            //Configure Log4Net logging
            options.IocManager.IocContainer.AddFacility<LoggingFacility>(
                f => f.UseAbpLog4Net().WithConfig(_hostingEnvironment.IsDevelopment()
                        ? "log4net.config"
                        : "log4net.Production.config")
            );

            options.PlugInSources.AddFolder(Path.Combine(_hostingEnvironment.WebRootPath, "Plugins"), SearchOption.AllDirectories);
        });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
    {
        //Initializes ABP framework.
        app.UseAbp(options =>
        {
            options.UseAbpRequestLocalization = false; //used below: UseAbpRequestLocalization
        });

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseStatusCodePagesWithRedirects("~/Error?statusCode={0}");
            app.UseExceptionHandler("/Error");
        }

        app.Use(async (context, next) => { await next(); if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value)) { context.Request.Path = "/index.html"; await next(); 
        
        } });
      // app.UseDefaultFiles(new DefaultFilesOptions { DefaultFileNames = new List<string> { "index.html" }});
       app.UseStaticFiles();
       app.UseRouting();

        app.UseCors(DefaultCorsPolicyName); //Enable CORS!

        app.UseAuthentication();
        app.UseJwtTokenMiddleware();

        if (bool.Parse(_appConfiguration["IdentityServer:IsEnabled"]))
        {
            app.UseJwtTokenMiddleware("IdentityBearer");
            app.UseIdentityServer();
        }

        app.UseAuthorization();

        using (var scope = app.ApplicationServices.CreateScope())
        {
            if (scope.ServiceProvider.GetService<DatabaseCheckHelper>().Exist(_appConfiguration["ConnectionStrings:Default"]))
            {
                app.UseAbpRequestLocalization();
            }
        }

        if (WebConsts.HangfireDashboardEnabled)
        {
            //Hangfire dashboard &server(Enable to use Hangfire instead of default job manager)
            app.UseHangfireDashboard(WebConsts.HangfireDashboardEndPoint, new DashboardOptions
            {

                // Authorization = new[] { new AbpHangfireAuthorizationFilter(AppPermissions.Pages_Administration_HangfireDashboard) }
            });

            var options = new BackgroundJobServerOptions
            {
                Queues = new[] { "WindowsService", "default" }
            };
            app.UseHangfireServer(options);


            RecurringJob.AddOrUpdate<IHangFireNotificationAppService>("Daily CSCS/ ECS Card Check", dd => dd.CheckCSCSECSCardValid(), Cron.Daily(8));
            RecurringJob.AddOrUpdate<IHangFireAppService>("Check access revocation", dd => dd.CheckForAccessRevocation(), "*/5 * * * *");
            RecurringJob.AddOrUpdate<IHangFireAppService>("Monthly Co2Report", mm => mm.MonthlyCo2ReportJob(), Cron.Daily(21));
            RecurringJob.AddOrUpdate<IHangFireAppService>("Weekly Co2Report", ww => ww.WeeklyCo2ReportJob(), Cron.Weekly(DayOfWeek.Friday, 21));
            RecurringJob.AddOrUpdate<IHangFireAppService>("Daily Co2Report", dd => dd.DailyCo2ReportJob(), Cron.Daily(21));
            RecurringJob.AddOrUpdate<IHangFireAppService>("Get Job Request", rs => rs.GetJobRequestResult(), "*/20 * * * *");
            RecurringJob.AddOrUpdate<IHangFireNotificationAppService>
                ("Send Warning Notification", r => r.SendNotificationForHangFire(),
                "*/10 * * * *");

         
        }

        if (bool.Parse(_appConfiguration["Payment:Stripe:IsActive"]))
        {
            StripeConfiguration.ApiKey = _appConfiguration["Payment:Stripe:SecretKey"];
        }

       

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapHub<AbpCommonHub>("/signalr");
            endpoints.MapHub<ChatHub>("/signalr-chat");

            endpoints.MapControllerRoute("defaultWithArea", "{area}/{controller=Home}/{action=Index}/{id?}");
            endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");

            if (bool.Parse(_appConfiguration["HealthChecks:HealthChecksEnabled"]))
            {
                endpoints.MapHealthChecks("/health", new HealthCheckOptions()
                {
                    Predicate = _ => true,
                    ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
                });
            }
        });

        if (bool.Parse(_appConfiguration["HealthChecks:HealthChecksEnabled"]))
        {
            if (bool.Parse(_appConfiguration["HealthChecks:HealthChecksUI:HealthChecksUIEnabled"]))
            {
                app.UseHealthChecksUI();
            }
        }

        if (WebConsts.SwaggerUiEnabled)
        {
            // Enable middleware to serve generated Swagger as a JSON endpoint
            app.UseSwagger();
            // Enable middleware to serve swagger-ui assets (HTML, JS, CSS etc.)

            app.UseSwaggerUI(options =>
            {
                options.SwaggerEndpoint(_appConfiguration["App:SwaggerEndPoint"], "API V1");
                options.IndexStream = () => Assembly.GetExecutingAssembly()
                    .GetManifestResourceStream("inteliProCS.Web.wwwroot.swagger.ui.index.html");
                options.InjectBaseUrl(_appConfiguration["App:ServerRootAddress"]);
            }); //URL: /swagger
        }
    }

    private void ConfigureKestrel(IServiceCollection services)
    {
        services.Configure<Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerOptions>(options =>
        {
            options.Listen(new System.Net.IPEndPoint(System.Net.IPAddress.Any, 443),
                listenOptions =>
                {
                    var certPassword = _appConfiguration.GetValue<string>("Kestrel:Certificates:Default:Password");
                    var certPath = _appConfiguration.GetValue<string>("Kestrel:Certificates:Default:Path");
                    var cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(certPath, certPassword);
                    listenOptions.UseHttps(new HttpsConnectionAdapterOptions()
                    {
                        ServerCertificate = cert
                    });
                });
        });
    }
}

}

I tried the web.config

This doesn't work either


10 Answer(s)
  • User Avatar
    0
    zony created
    Support Team

    Hi GarethWright, Can you share the contents of web.conf? Generally speaking, it will be resolved after rewriting the route, please refer to: -[https://router.vuejs.org/guide/essentials/history-mode.html#example-server-configurations](https://router.vuejs.org/guide/essentials/history-mode.html#example -server-configurations) -[https://stackoverflow.com/questions/43785928/angular-2-hosted-on-iis-http-error-404](https://stackoverflow.com/questions/43785928/angular-2-hosted-on -iis-http-error-404)

  • User Avatar
    0
    GarethWright created

    web.config in wwwroot dir

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <system.webServer>
        <staticContent>
          <remove fileExtension=".json" />
          <mimeMap fileExtension=".json" mimeType="application/json" />
    	  <mimeMap fileExtension="woff" mimeType="application/font-woff" />
          <mimeMap fileExtension="woff2" mimeType="application/font-woff" /> 
        </staticContent>
        <!-- IIS URL Rewrite for Angular routes -->
        <rewrite>
          <rules>
            <rule name="Angular Routes" enabled="true" stopProcessing="true">
              <match url=".*" />
              <conditions logicalGrouping="MatchAll">
                <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
              </conditions>
              <action type="Rewrite" url="/" />
            </rule>
          </rules>
        </rewrite>
            <defaultDocument>
                <files>
                    <clear />
                    <add value="index.html" />
                </files>
            </defaultDocument>
      </system.webServer>
    </configuration>
    
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @GarethWright

    Could you delete the URL rewrite rule in IIS and place this web.confi into the root directory of your published app ? Not under wwwroot folder.

    Thanks,

  • User Avatar
    0
    GarethWright created

    As that folder already contains web.config assume merging the two?

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <location path="." inheritInChildApplications="false">
        <system.webServer>
          <handlers>
            <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
          </handlers>
          <aspNetCore processPath=".\projectname.Web.Host.exe" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" />
        </system.webServer>
      </location>
    </configuration>
    <!--ProjectGuid: 9fc37c62-2105-4d32-9724-7323b959504b-->
    
    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <location path="." inheritInChildApplications="false">
        <system.webServer>
          <handlers>
            <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
          </handlers>
          <aspNetCore processPath=".\projectname.Web.Host.exe" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" />
       
    <staticContent>
          <remove fileExtension=".json" />
          <mimeMap fileExtension=".json" mimeType="application/json" />
    	  <mimeMap fileExtension="woff" mimeType="application/font-woff" />
          <mimeMap fileExtension="woff2" mimeType="application/font-woff" /> 
        </staticContent>
        <!-- IIS URL Rewrite for Angular routes -->
        <rewrite>
          <rules>
            <rule name="Angular Routes" enabled="true" stopProcessing="true">
              <match url=".*" />
              <conditions logicalGrouping="MatchAll">
                <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
              </conditions>
              <action type="Rewrite" url="/" />
            </rule>
          </rules>
        </rewrite>
            <defaultDocument>
                <files>
                    <clear />
                    <add value="index.html" />
                </files>
            </defaultDocument>
     </system.webServer>
      </location>
    </configuration>
    <!--ProjectGuid: 9fc37c62-2105-4d32-9724-7323b959504b-->
    
  • User Avatar
    0
    GarethWright created

    When I do that I get ERR_TOO_MANY_REDIRECTS

  • User Avatar
    0
    GarethWright created

  • User Avatar
    0
    ismcagdas created
    Support Team

    @GarethWright Do you use Merged solution ? Is it possible for us to access yoru server ? If so, could you send an email to [email protected] ?

  • User Avatar
    0
    GarethWright created

    Replied to you via email

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @GarethWright

    Thanks, we can continue via email.

  • User Avatar
    0
    GarethWright created

    For info:

    The issue was because I had used https://www.nuget.org/packages/Hangfire.Dashboard.Customize/ to customise the Hangfire Dashboard.

    It's middleware and but doesn't allow any other middleware to run futher down the chain.