pbz
pbz

Reputation: 9085

ASP.NET Core map route to static file handler

I'm working on a ASP.NET Core website (previously named ASP.NET 5 / vNext) with Angular. In order for Angular to work I need to have a catch-all route:

app.UseStaticFiles(); 
app.UseMvc(routes =>
        {
            // Angular fallback route
            routes.MapRoute("angular", "{*url}", new { controller = "Home", action = "Index" });                
        });

I also have a few files/folders in wwwroot, like:

wwwroot/app
wwwroot/assets
wwwroot/lib

When any requests are made to these paths, for example http://example.com/assets/css/test.css, and the file (test.css) does NOT exist, it should not continue to the fallback route. It should return a 404.

Right now, if the file does not exist it returns the Angular HTML. So, how can I tell it that any path that starts with '/assets' should only be routed / served by UseStaticFiles?

Upvotes: 8

Views: 14427

Answers (3)

pbz
pbz

Reputation: 9085

This seems to work:

app.MapWhen(
    context => {
        var path = context.Request.Path.Value.ToLower();
        return
            path.StartsWith("/assets") ||
            path.StartsWith("/lib") ||
            path.StartsWith("/app");
    },
    config => config.UseStaticFiles());

However, I'm not sure if there are any performance (or other type of) implications. I'll update if I come across any.

Upvotes: 11

Maxim
Maxim

Reputation: 13458

If you are using attribute template routing then you can apply this elegant solution:

[HttpGet("")]
[HttpGet("{*route:regex(^(?!skipped).*$)}")]
public async Task<IActionResult> Default(string route) { throw new NotImplementedException(); }

So all routes started with skipped will be ignored by this action.
If you want multiple prefixes or anything else then just update regex for your needs.
First Get attribute is needed to handle root of site (in this case route variable is null).

Upvotes: -1

Ilya Chernomordik
Ilya Chernomordik

Reputation: 30205

It is strange that this common case (since many use SPA) is not covered almost anywhere and everyone has to invent something. I have found that the best way to do that is to add constraint (e.g. do not use the route if there is /api or "." in the path). Unfortunately this is not supported out of the box, but you can write this constraint yourself or copy the one I wrote from here.

There are a bit more details in this post. But generally the code looks like this:

 app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "api",
            template: "api/{controller}/{action}");

        routes.MapRoute(
            name: "angular",
            template: "{*url}",
            defaults: new {controller = "Home", action = "Index"},
            constraints: new {url = new DoesNotContainConstraint(".", "api/") });                
    });

P.S. Perhaps this constraint exist out of the box now, but I have not found one. Alternatively a RegEx can be used, but simple one should be way faster.

Upvotes: 3

Related Questions