10

How can I accomplish URL rewriting in ASP.NET Core RC2? Migrating from RC1 to RC2 broke my Angular 2 routing when I refresh the page.

I was using a rule like this before in my web.config located in my wwwroot. With RC2 I'm not even sure if I'm supposed to have a web.config in my wwwroot anymore, or if I'm just supposed to have the one in the base of my project.

This is my base web.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
    </handlers>
    <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" forwardWindowsAuthToken="true" stdoutLogEnabled="true" />
  </system.webServer>
</configuration>

And this is my wwwroot web.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <!--Redirect selected traffic to index -->
        <rule name="Index Rule" stopProcessing="true">
          <match url=".*" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_URI}" matchType="Pattern" pattern="^/api/" negate="true" />
            <add input="{REQUEST_URI}" matchType="Pattern" pattern="^/account/" negate="true" />
          </conditions>
          <action type="Rewrite" url="/index.html" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

When I refresh an angular 2 route, I get a Status Code: 404; Not Found from ASP.NET

twilliams
  • 475
  • 1
  • 6
  • 20

3 Answers3

4

I found a working solution here.

Below is the code in my Configure method that fixed the issue for me. But be careful, the declaration order matters.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));

    if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();
    }

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

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

    app.UseDefaultFiles();
    app.UseStaticFiles();

    app.UseMvc(routes => {
        routes.MapRoute("Default", "api/{controller}/{action}/{id?}");
    });
}
Manos Pasgiannis
  • 1,693
  • 1
  • 18
  • 30
  • This is the answer I used to resolve the same exact problem. It has the benefit not found in the accepted answer as satisfying the OP's desire to use the minimal amount of .NET code. – Gustyn Jul 07 '17 at 12:33
1

I found solution by Steve Sanderson, seems to work. he wrote extension to RouteBuilder. You can configure it in Setup.cs by calling extension method MapSpaFallbackRoute

https://github.com/aspnet/JavaScriptServices

app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
                routes.MapSpaFallbackRoute("spa-fallback", new { controller = "Home", action = "Index" });
            });
Adam Kopciński
  • 505
  • 4
  • 12
  • This is the solution I got around to just now, and it's brilliant. All you do is install the package... and in my case I only had to add the MapSpaFallbackRoute, and in my Index Controller for home all I did was return File("index.html", "text/html") and everything works brilliantly. Thanks! – twilliams Jul 19 '16 at 14:20
  • Do you have to add a controller for this to work? I'm coming from java/node world and new to MS-world, but trying to keep my project as clean as possible. i.e. nothing .Net specific – Bulan Sep 14 '16 at 13:47
0

I had the exact same issue. In fact, for me, the IIS Express Server did not even start when the rewrite rule was included in the web.config file. Given this I dug around for some other way to do the same thing without relying on rewrite rules. I found that you can use the MapWhen function in your startup.cs file to send anything not handled by MVC back to index.html.

The below code has been added to the Configure method of the Startup.cs class after the app.UseMvc() call.

        app.UseMvc();

        // this serves "index.html" from the wwwroot folder when 
        // a route not containing a file extension is not handled by MVC.
        app.MapWhen(context =>
        {
            var path = context.Request.Path.Value.ToLower();
            return path.Contains(".");
        },
            branch =>
            {
                branch.Use((context, next) =>
                {
                    context.Request.Path = new PathString("/index.html");
                    return next();
                });

                branch.UseStaticFiles();
            });

So far this looks like its working but I need to do some more testing to see if there are any side effects. Personally the rewrite rule seemed a better solution but this does appear to get me past the issue.

G. Zidar
  • 195
  • 2
  • 8
  • Does this handle allowing other mime types or API calls through? We have json for locales and APIs on the same server... – droidalmatter May 25 '16 at 00:06
  • The first part of the mapwhen call with the context is where you decide what calls go to MVC and what goes to the static file handler. So you can explicitly route only your API calls to the server and send everything else back to your angular (or whatever) app. In my specific case we sent only any path that contains "/api/" to MVC. – G. Zidar May 26 '16 at 00:07
  • Found this middleware code helpful. We are using something similar in Asp.net core 1 RC1 project. Will need to port it to RC2/RTM... https://github.com/BrainCrumbz/AWATTS/tree/master/src/WebPackAngular2TypeScript/Routing – droidalmatter Jun 08 '16 at 15:58