title: Custom Router for Maintenance
body: <p>I would like my ASP.NET Core MVC site to route all requests to a particular controller/action method whenever a particular file exists. The idea is that I can display a "site down for maintenance" page on an as-needed basis, just by creating a particular empty file.</p>
  
  <p>After playing around with writing some custom middleware, it dawned on me that I should be able to create a custom <code>IRouter</code> which does this. Every route request should map to the "maintenance" route when that particular file exists. But I can't get it to work.</p>
  
  <p>Here's the definition of the custom router:</p>
  
  <pre><code>public class OfflineRouteHandler : IRouter
  {
      private readonly string _path;
      private readonly IPAddress _remote;
  
      public OfflineRouteHandler( string offlinePath, string remoteIP )
      {
          _path = offlinePath;
          _remote = IPAddress.Parse( remoteIP );
      }
  
      public VirtualPathData GetVirtualPath( VirtualPathContext context )
      {
          // this returns a value...but RouteAsync is never called
  
          StringBuilder path = new StringBuilder();
  
          if( context.AmbientValues.ContainsKey( "controller" ) )
              path.Append( context.AmbientValues["controller"] );
  
          if( context.AmbientValues.ContainsKey("action") )
          {
              if( path.Length &gt; 0 ) path.Append( "/" );
              path.Append( context.AmbientValues["action"] );
          }
  
          return new VirtualPathData( this, "/" + path.ToString() );
      }
  
      public async Task RouteAsync( RouteContext context )
      {
          bool authorized = ( context.HttpContext.Connection.RemoteIpAddress == _remote );
  
          if( File.Exists(_path) &amp;&amp; authorized )
          {
              // just for testing... but the method never gets called
              var i = 9;
              i++;
          }
  
          context.IsHandled = true;
      }
  }
  </code></pre>
  
  <p>I invoke it in <code>Configure()</code> in Startup.cs as follows:</p>
  
  <pre><code>string offlinePath = Path.Combine( Directory.GetParent( env.WebRootPath ).FullName, "offline.txt" );
  
  app.UseMvc(routes =&gt;
  {
      routes.Routes.Add( new TemplateRoute( new OfflineRouteHandler( offlinePath, "50.3.3.2" ), "home/offline", new DefaultInlineConstraintResolver(routeOptions)) );
  
      routes.MapRoute(
          name: "default",
          template: "{controller=Home}/{action=Index}/{id?}");
  });
  </code></pre>
  
  <p><code>routeOptions</code> gets passed into the call to <code>Configure();</code></p>
  
  <p>Any help would be greatly appreciated!</p>