自定义路由器进行维护

时间:2016-06-15 20:22:43

标签: asp.net-core asp.net-core-mvc

我希望我的ASP.NET Core MVC站点在特定文件存在时将所有请求路由到特定的控制器/操作方法。我的想法是,我可以显示一个"网站进行维护"页面根据需要,只需创建一个特定的空文件。

在编写了一些自定义中间件之后,我突然意识到我应该能够创建一个自定义IRouter来实现这一点。每个路径请求都应映射到"维护"该特定文件存在时的路由。但我无法让它发挥作用。

以下是自定义路由器的定义:

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 > 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) && authorized )
        {
            // just for testing... but the method never gets called
            var i = 9;
            i++;
        }

        context.IsHandled = true;
    }
}

我在Startup.cs中的Configure()中调用它,如下所示:

string offlinePath = Path.Combine( Directory.GetParent( env.WebRootPath ).FullName, "offline.txt" );

app.UseMvc(routes =>
{
    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?}");
});

routeOptions被传递到对Configure();

的调用中

非常感谢任何帮助!

1 个答案:

答案 0 :(得分:1)

这是未经测试的,但我选择了中间件方法。

它使用与UseStatusCodePagesWithReExecute函数类似的方法,因为它使用路径修改context.Request.Path。我已使用Options pattern加载OfflineMiddleware的设置。

基本上,当文件存在时,中间件会修改所需路径的路径" home / offline",并继续执行mvc管道。

由于我们已在中间件之前添加了UseStaticFiles(),因此将提供离线页面上的所有静态文件 - 只有截获通过MVC管道的请求才会被拦截,所有这些请求都将被截获打到家/离线。

public class Startup
{
  //Partial Starup class
  public void ConfigureServices(IServiceCollection services)
  {
    services.Configure<OfflineMiddlewareSettings>(settings =>
    { 
        settings.OfflinePath = "thePath";
        settings.RemoteIP = "50.3.3.2";
    });

    // Add framework services.
    services.AddMvc();
  }

  public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IOptionsMonitor<MyValues> monitor)
  {
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    app. UseStaticFiles();

    app.UseMiddleware<OfflineMiddleware>();
    app.UseMvc();
  }

}

public class OfflineMiddleware
{
    private readonly RequestDelegate _next;
    private readonly string _path;
    private readonly IPAddress _remote;

    public OfflineMiddleware(RequestDelegate next, IOptions<OfflineMiddlewareSettings> settings)
    {
        _next = next;
        _path = settings.Value.OfflinePath;
        _remote = IPAddress.Parse(settings.Value.OfflinePath);
    }

    public async Task Invoke(HttpContext context)
    {
        bool authorized = (context.Connection.RemoteIpAddress == _remote);

        if (File.Exists(_path) && authorized)
        {
            context.Request.Path = "home/offline";   
        }

        await _next.Invoke(context);
    }
}

public class OfflineMiddlewareSettings
{
    public string OfflinePath { get; set; }
    public string RemoteIP { get; set; }
}