0

Technical Information

Scenario

I have an AngularJS single page app (SPA) that I'm trying to pre-render via an external PhantomJS service.

I want MVC's route handler to ignore the route /?_escaped_fragment_={fragment}, so the request can be handled directly by ASP.NET and thus passed on to IIS to proxy the request.

In Theory

**I could be wrong. As far as I'm aware, custom routing takes precedence as it's done before the Umbraco routes are registered. However I'm unsure whether telling MVC to ignore a route would also prevent Umbraco from handling that route.

In Practise

I have attempted to ignore the routes with the following:

Attempt one:

routes.Ignore("?_escaped_fragment_={*pathInfo}");

This throws an error: The route URL cannot start with a '/' or '~' character and it cannot contain a '?' character.

Attempt two:

routes.Ignore("{*escapedfragment}", new { escapedfragment = @".*\?_escaped_fragment_=\/(.*)" });

This didn't result in an error, however Umbraco still picked up the request and handed me back my root page. Regex validation on Regexr.

Questions

  • Can MVC actually ignore a route based on its query string?
  • Is my knowledge of Umbraco's routing correct?
  • Is my regex correct?
  • Or am I missing something?
Community
  • 1
  • 1
martinthebeardy
  • 742
  • 1
  • 7
  • 18

1 Answers1

2

The built-in routing behavior doesn't take the query string into consideration. However, routing is extensible and can be based on query string if needed.

The simplest solution is to make a custom RouteBase subclass that can detect your query string, and then use the StopRoutingHandler to ensure the route doesn't function.

public class IgnoreQueryStringKeyRoute : RouteBase
{
    private readonly string queryStringKey;

    public IgnoreQueryStringKeyRoute(string queryStringKey)
    {
        if (string.IsNullOrWhiteSpace(queryStringKey))
            throw new ArgumentNullException("queryStringKey is required");
        this.queryStringKey = queryStringKey;
    }

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        if (httpContext.Request.QueryString.AllKeys.Any(x => x == queryStringKey))
        {
            return new RouteData(this, new StopRoutingHandler());
        }

        // Tell MVC this route did not match
        return null;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        // Tell MVC this route did not match
        return null;
    }
}

Usage

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        // This route should go first
        routes.Add(
            name: "IgnoreQuery",
            item: new IgnoreQueryStringKeyRoute("_escaped_fragment_"));


        // Any other routes should be registered after...

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}
NightOwl888
  • 55,572
  • 24
  • 139
  • 212