我希望我的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();
非常感谢任何帮助!
答案 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; }
}