9

I'm upgrading my project to ASPNET5. My application is a AngularJS Web App that uses HTML5 Url Routing ( HTML5 History API ).

In my previous app I used the URL Rewrite IIS Module with code like:

<system.webServer>
  <rewrite>
    <rules>
      <rule name="MainRule" 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}" matchType="Pattern" pattern="api/(.*)" negate="true" />
          <add input="{REQUEST_URI}" matchType="Pattern" pattern="signalr/(.*)" negate="true" />
        </conditions>
        <action type="Rewrite" url="Default.cshtml" />
      </rule>
    </rules>
  </rewrite>
<system.webServer>

I realize I could port this but I want to minimize my windows dependencies. From my reading I think I should be able to use ASP.NET 5 Middleware to accomplish this.

I think the code would look something like this but I think I'm pretty far off.

app.UseFileServer(new FileServerOptions
{
    EnableDefaultFiles = true,
    EnableDirectoryBrowsing = true
});

app.Use(async (context, next) =>
{
    if (context.Request.Path.HasValue && context.Request.Path.Value.Contains("api"))
    {
        await next();
    }
    else
    {
        var redirect = "http://" + context.Request.Host.Value;// + context.Request.Path.Value;
        context.Response.Redirect(redirect);
    }
});

Essentially, I'm wanting to route anything that contains /api or /signalr. Any suggestions on best way to accomplish this in ASPNET5?

amcdnl
  • 8,470
  • 12
  • 63
  • 99

3 Answers3

6

You were on the right track, but rather than sending back a redirect, we just want to rewrite the path on the Request. The following code is working as of ASP.NET5 RC1.

app.UseIISPlatformHandler();

// This stuff should be routed to angular
var angularRoutes = new[] {"/new", "/detail"};

app.Use(async (context, next) =>
{
    // If the request matches one of those paths, change it.
    // This needs to happen before UseDefaultFiles.
    if (context.Request.Path.HasValue &&
        null !=
        angularRoutes.FirstOrDefault(
        (ar) => context.Request.Path.Value.StartsWith(ar, StringComparison.OrdinalIgnoreCase)))
    {
        context.Request.Path = new PathString("/");
    }

    await next();
});

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

One issue here is that you have to specifically code your angular routes into the middleware (or put them in a config file, etc).

Initially, I tried to create a pipeline where after UseDefaultFiles() and UseStaticFiles() had been called, it would check the path, and if the path was not /api, rewrite it and send it back (since anything other than /api should have been handled already). However, I could never get that to work.

Bill
  • 403
  • 4
  • 11
  • why hold the angular routes on the server side, thats stupid. All API calls to the server start with 'api' you can easily use .StartsWith('api',request.Path) to determine wether to set "/" or not, right? – Elisabeth Nov 08 '17 at 07:37
  • 2
    You could certainly invert the logic to hold the back end routes (in your case, just "api") rather than the front end routes. In my case it makes more sense to do the former, because we have relatively few front end routes and several back end routes aside from "api". Either way it amounts to the same thing. You rewrite the routes that need to go to Angular. Keep in mind that if your ASP.NET app is also responsible for serving the files (html, css, etc), you'll need to account for those paths in addition to "api". – Bill Nov 09 '17 at 10:14
0

I'm using:

app.UseMvc(routes =>
{
    routes.MapRoute(
        name:"Everything", 
        template:"{*UrlInfo}", 
        defaults:new {controller = "Home", action = "Index"});
}

This will cause all routes to hit the Home Index page. When I need routes to fall outside this, I add them before this route as this becomes a catch all route.

Rangoric
  • 2,739
  • 1
  • 18
  • 18
-2

Why not use routing feature in MVC? In the Configure method in Startup.cs, you could modify the following:

        // inside Configure method in Startup.cs
        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller}/{action}/{id?}",
                defaults: new { controller = "Home", action = "Index" });

            // Uncomment the following line to add a route for porting Web API 2 controllers.
            // routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}");
        });  
Michael Palermo
  • 296
  • 2
  • 9
  • Doesn't work for HTML5 history, you need to only route assets/api through everything else should return the index file. – amcdnl Jul 13 '15 at 19:40