在上一个问题How to route web pages on a mixed MVC and Web Forms中,我试图进一步扩展我将所有Web窗体(* .aspx)路由到网站上的特定子文件夹的想法。基本思想是检查所有请求以查看它们是否映射到指定的“Web表单页面”文件夹中的现有.aspx页面。例如,如果所有.aspx页面都存在于'〜/ WebPages'的文件夹结构中......
/MyPage.aspx => /WebPages/MyPage.aspx
/SubFolder/MyotherPage.aspx => /WebPages/SubFolder/MyOtherPage.aspx
此外,我想通过删除.aspx扩展来简化URL,所以
/ MyPage => /网页/我的页面
/SubFolder/MyotherPage.aspx => /WebPages/SubFolder/MyotherPage.aspx
为此,我需要考虑每个请求,因为我认为不可能定义特定的路由或约束。为此,我实现了以下路由配置。
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add(
"rootforms",
new Route(
"{*pathInfo}",
new DirectoryRouteHandler(virtualDir: "~/WebPages")
)
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new
{
controller = "Home",
action = "Index",
id = UrlParameter.Optional
},
namespaces: new[] {
"MultiApp.Web.Controllers"
}
);
}
}
并定义了自定义路由处理程序,如下所示。
public class DirectoryRouteHandler : IRouteHandler
{
private readonly string _virtualDir;
public DirectoryRouteHandler(string virtualDir)
{
_virtualDir = virtualDir;
}
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var routeValues = requestContext.RouteData.Values;
if (!routeValues.ContainsKey("pathInfo"))
{
return null; /* this doesn't work - must be a RouteHandler */;
}
var path = routeValues["pathInfo"] as string;
if (String.IsNullOrWhiteSpace(path))
{
path = "Default.aspx";
}
// add the .aspx extension if required
if (!path.EndsWith(".aspx")) { path += ".aspx"; }
// build the test path
var pageVirtualPath = string.Format("{0}/{1}", _virtualDir, path);
string filePath = requestContext.HttpContext.Server.MapPath(pageVirtualPath);
// check to see if the physical .aspx file exists, if not exit this handler
if (!File.Exists(filePath))
{
return null; /* this doesn't work - must be a RouteHandler */;
}
return new PageRouteHandler(pageVirtualPath, true).GetHttpHandler(requestContext);
}
}
我希望能够做的是返回一个PageRouteHandler对象(如前一个问题所示),或退出此处理程序,将责任传递回默认路由机制。
这是可能的,还是我完全吠叫了错误的树?我只是注册一个简单的IHttpHandler并单独留下路由会更好吗?
答案 0 :(得分:0)
我想我找到了解决方法。不是通过管理路由来尝试实现此功能,而是使用自定义HttpModule。这是代码。
public class WebFormsHttpHandler
: IHttpModule
{
// All Web Form (*.aspx) pages will exist in this folder hierarchy
public const string WebFormsRootFolder = "~/WebPages";
#region Constructor
public WebFormsHttpHandler()
{
}
#endregion Constructor
#region IHttpModule Methods
public void Dispose()
{
/* Nothing to dispose */
}
#endregion Constructor
// Wire up the interesting events
public void Init(HttpApplication context)
{
context.BeginRequest += context_BeginRequest;
context.AuthorizeRequest += context_AuthorizeRequest;
context.PreRequestHandlerExecute += context_PreRequestHandlerExecute;
}
#region BeginRequest
// Capture the original request path so we can restore it to the browser
// in the PreRequestHandlerExecute event if required
void context_BeginRequest(object sender, EventArgs e)
{
var context = ((HttpApplication)sender).Context;
var path = context.Request.Url.AbsolutePath;
context.Items["originalUrl"] = path;
}
#endregion BeginRequest
#region AuthorizeRequest
void context_AuthorizeRequest(object sender, EventArgs e)
{
var context = ((HttpApplication)sender).Context;
string requestPath = context.Request.Url.AbsolutePath ?? "";
string filePath = context.Server.MapPath(requestPath);
// Check for physical existence
if (File.Exists(filePath))
{
return;
}
var virtualPath = WebFormsRootFolder;
if (!requestPath.StartsWith("/")) { virtualPath += "/"; }
virtualPath += requestPath;
filePath = context.Server.MapPath(virtualPath);
// Is the virtualPath a directory?
if (Directory.Exists(filePath))
{
if (!virtualPath.EndsWith("/")) { virtualPath += "/"; }
virtualPath += "Default.aspx";
}
else if (!virtualPath.EndsWith(".aspx")) {
virtualPath += ".aspx";
}
filePath = context.Server.MapPath(virtualPath);
if (!File.Exists(filePath))
{
return;
}
/*
** Should I set a context.Response.StatusCode here?
*/
context.RewritePath(virtualPath);
}
#endregion AuthorizeRequest
#region PreRequestHandlerExecute
// Restore the original request path on the browser - the user doesn't
// need to know what's happened
void context_PreRequestHandlerExecute(object sender, EventArgs e)
{
var context = ((HttpApplication)sender).Context;
string originalUrl = context.Items["originalUrl"] as string;
if (originalUrl != null)
{
context.RewritePath(originalUrl);
}
}
#endregion PreRequestHandlerExecute
}
<system.webServer>
<modules>
<add name="WebFormsHttpHandler" type="MultiApp.Web.WebFormsHttpHandler" />
</modules>
</system.webServer>
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// WebForm Route Definitions
routes.MapPageRoute(
"product-details",
"product/{productid}",
"~/WebPages/SubFolder/Product.aspx"
);
// MVC Route Definitions
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new
{
controller = "Home",
action = "Index",
id = UrlParameter.Optional
},
namespaces: new[] {
"MultiApp.Web.Controllers"
}
);
}
我已经使用各种各样的URL构造对其进行了测试,它似乎可以按要求运行。如果有人有任何改进建议,请告诉我。
我要感谢Rahul Rajat Singh的项目Implementing HTTPHandler and HTTPModule in ASP.NET,这是一个很大的帮助。