简体   繁体   中英

.NET Core, Angular2, NancyFX - 404 changing URL in browser

When serving the application with .NET Core static files I'm unable to change the URL in the browser. When doing so I'm given the

404 - Not Found

Nancy error page.

The only URL that's working is the base URL, localhost:5000. Changing the URL to localhost:5000/reservations gives me 404. Pressing F5 when not on the base URL will also result in a 404.

If I use the browsersync url, localhost:4200, everything works and I can change the URL and press F5 without 404. This is what I'm doing when developing but not when it's deployed on the server using IIS.

Running the application in IIS Express

  1. ng build (files are copied over to wwwroot along with index.html)

  2. start IIS Express

Startup.cs

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddEnvironmentVariables();
        Configuration = builder.Build();

        env.ConfigureNLog("nlog.config");
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication(IISDefaults.AuthenticationScheme);

        services.AddMvc(config =>
        {
            var policy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();
            config.Filters.Add(new AuthorizeFilter(policy));
        });

        services.AddMvc();

        services.InjectServices();

        services.AddOptions();

        services.Configure<Endpoints>(Configuration.GetSection("Endpoints"));

        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

        services.AddSingleton<IConfiguration>(Configuration);
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        app.Use(async (context, next) =>
        {
            await next();
            if (!context.Request.Path.Value.StartsWith("/api/"))
            {
                context.Request.Path = "/index.html";
                await next();
            }
        });

        app.UseDefaultFiles();

        app.UseStaticFiles();

        loggerFactory.AddNLog();

        app.AddNLogWeb();

        app.UseOwin(x => x.UseNancy(new NancyOptions
        {
            Bootstrapper = new Bootstrapper(app)
        }));
    }
}

Bootstrapper.cs

public class Bootstrapper : DefaultNancyBootstrapper
{
    readonly IApplicationBuilder _app;

    public Bootstrapper(IApplicationBuilder app)
    {
        _app = app;
    }

    protected override void ConfigureApplicationContainer(TinyIoCContainer container)
    {
        base.ConfigureApplicationContainer(container);

        container.Register<IOptions<Endpoints>>(_app.ApplicationServices.GetService<IOptions<Endpoints>>());

        container.Register<IReservationService>(_app.ApplicationServices.GetService<IReservationService>());
    }
}

wwwroot

在此处输入图片说明

index.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>XXX</title>
    <base href="/">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link rel="icon" type="image/x-icon" href="XXX">
    <link href="styles.61cc257ef8131303860b.bundle.css" rel="stylesheet" />
</head>
<body>
    <app-root></app-root>
    <script type="text/javascript" src="inline.f68c652d205feae6e02a.bundle.js"></script>
    <script type="text/javascript" src="polyfills.756a44edc7e0a68ce65c.bundle.js"></script>
    <script type="text/javascript" src="vendor.940a3ce39a746f717f7b.bundle.js"></script>
    <script type="text/javascript" src="main.d5f9dd82a3600822cae2.bundle.js"></script>
</body>
</html>

I understand that there is some problem with the handling of static content from the server but I can't seem to figure it out.

How can I navigate around using the browser URL when hosting the Angular application in .NET Core?

Update 1:

After adding:

PerformPassThrough = (context => context.Response.StatusCode == HttpStatusCode.NotFound)

the 404 error message goes away but page is now blank without any error message except the 404 in the console..

在此处输入图片说明

IMO the middleware you wrote should be after the app.UseDefaultFiles(); and app.UseStaticFiles(); And you are only handling API requests. Try to rewrite it a little bit to also handle 404 errors and to not handle requests with extensions:

app.Use(async (context, next) =>
{
    await next();

    if (context.Response.StatusCode == 404
        && !Path.HasExtension(context.Request.Path.Value)
        && !context.Request.Path.Value.StartsWith("/api/"))
    {
        context.Request.Path = "/index.html";
        await next();
    }
});

You need to remove the first await next(); . That's sending the request to /reservations down the pipeline, before rewriting the URL to index.html .

When it hits Nancy, it'll see if it can handle /reservations , which it can't, and render a 404 page.

  1. Modified Startup.cs
  2. Added module that returns index.html for all requests.
  3. Configured root path in bootstrapper.cs.

Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    //For serving index.html on baseurl - this can we done in AppNancyModule aswell: Get("/", _ => View["index"]);
    app.UseDefaultFiles();

    app.UseStaticFiles();

    loggerFactory.AddNLog();

    app.AddNLogWeb();

    app.UseOwin(x => x.UseNancy(new NancyOptions
    {
        Bootstrapper = new Bootstrapper(app, env)
    }));
}

AppNancyModule

public class AppNancyModule : NancyModule
{
    public AppNancyModule()
    {
        //Get("/", _ => View["index"]);

        Get(@"^(.*)$", _ => View["index"]);
    }
}

Bootstrapper.cs

public class AppRootPathProvider : IRootPathProvider
{
    private readonly IHostingEnvironment _environment;

    public AppRootPathProvider(IHostingEnvironment environment)
    {
        _environment = environment;
    }
    public string GetRootPath()
    {
        return _environment.WebRootPath;
    }
}

public class Bootstrapper : DefaultNancyBootstrapper
{
    readonly IApplicationBuilder _app;

    protected override IRootPathProvider RootPathProvider { get; }

    public Bootstrapper(IApplicationBuilder app, IHostingEnvironment environment)
    {
        RootPathProvider = new AppRootPathProvider(environment);
        _app = app;
    }

    protected override void ConfigureApplicationContainer(TinyIoCContainer container)
    {
        base.ConfigureApplicationContainer(container);

        container.Register<IOptions<Endpoints>>(_app.ApplicationServices.GetService<IOptions<Endpoints>>());

        container.Register<IReservationService>(_app.ApplicationServices.GetService<IReservationService>());
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM