ASP.Net MVC 路由捕获所有 *.aspx 请求
Posted
技术标签:
【中文标题】ASP.Net MVC 路由捕获所有 *.aspx 请求【英文标题】:ASP.Net MVC route to catch all *.aspx requests 【发布时间】:2016-07-09 11:08:57 【问题描述】:这个必须之前已经被问过,但是在阅读了here、here、here 和here 之后,我无法推断相关部分以使其工作。我正在将一个旧的 Web 表单站点改造成 MVC,并希望捕获特定的传入 HTTP 请求,以便我可以发出 RedirectPermanent
(以保护我们的 Google 排名并避免用户因 404 而离开)。
我需要拦截所有以(或包含).aspx 文件结尾的请求,而不是拦截所有 传入请求,或解析某些id
值扩展名,例如
www.sample.com/default.aspx
www.sample.com/somedir/file.aspx
www.sample.com/somedir/file.aspx?foo=bar
应忽略对 MVC 路由的请求(正常处理)。
这是我目前所拥有的,除了 ASPXFiles
路线从未被击中。
public class RouteConfig
public static void RegisterRoutes(RouteCollection routes)
routes.IgnoreRoute("resource.axd/*pathInfo");
// never generates a match
routes.MapRoute(
name: "ASPXFiles",
url: "*.aspx",
defaults: new controller = "ASPXFiles", action = "Index"
);
// Used to process all other requests (works fine)
routes.MapRoute(
name: "Default",
url: "controller/action/id",
defaults: new controller = "Home", action = "Index", id = UrlParameter.Optional
);
这种类型的路由可以在 MVC 中设置吗?
【问题讨论】:
【参考方案1】:我正在展示在 MVC 中进行 301 重定向的正确方法,因为并非所有浏览器都能正确响应 301 重定向请求,您需要为用户提供继续选项而不是默认选项由 ASP.NET 生成的“对象已移动”页面。
RedirectAspxPermanentRoute
我们构建了一个自定义的 RouteBase
子类,用于检测 URL 何时以 .aspx
结尾并路由到我们的 SystemController
以设置 301 重定向。它要求您将 URL 映射(要匹配的 URL)传递给路由值(用于生成 MVC URL)。
public class RedirectAspxPermanentRoute : RouteBase
private readonly IDictionary<string, object> urlMap;
public RedirectAspxPermanentRoute(IDictionary<string, object> urlMap)
this.urlMap = urlMap ?? throw new ArgumentNullException(nameof(urlMap));
public override RouteData GetRouteData(HttpContextBase httpContext)
var path = httpContext.Request.Path;
if (path.EndsWith(".aspx"))
if (!urlMap.ContainsKey(path))
return null;
var routeValues = urlMap[path];
var routeData = new RouteData(this, new MvcRouteHandler());
routeData.Values["controller"] = "System";
routeData.Values["action"] = "Status301";
routeData.DataTokens["routeValues"] = routeValues;
return routeData;
return null;
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
return null;
请注意,第一次检查是针对 .aspx
扩展名,因此如果扩展名不匹配,则将完全跳过其余逻辑。这将为您的方案提供最佳性能。
系统控制器
我们设置SystemController
以像往常一样返回视图。如果浏览器因为 301 没有重定向,用户就会看到视图。
using System;
using System.Net;
using System.Web;
using System.Web.Mvc;
public class SystemController : Controller
//
// GET: /System/Status301/
public ActionResult Status301()
var routeValues = this.Request.RequestContext.RouteData.DataTokens["routeValues"];
var url = this.GetAbsoluteUrl(routeValues);
Response.CacheControl = "no-cache";
Response.StatusCode = (int)HttpStatusCode.MovedPermanently;
Response.RedirectLocation = url;
ViewBag.DestinationUrl = url;
return View();
private string GetAbsoluteUrl(object routeValues)
var urlBuilder = new UriBuilder(Request.Url.AbsoluteUri)
Path = Url.RouteUrl(routeValues)
;
var encodedAbsoluteUrl = urlBuilder.Uri.ToString();
return HttpUtility.UrlDecode(encodedAbsoluteUrl);
Status301.cshtml
遵循 MVC 的约定,并确保将其放在 /Views/System/
文件夹中。
因为它是您的 301 响应的视图,所以您可以使其与您网站其余部分的主题相匹配。所以,如果用户最终来到这里,这仍然是一个不错的体验。
视图将尝试通过 javascript 和通过 Meta-Refresh 自动重定向用户。这两个都可以在浏览器中关闭,但用户很可能会去他们应该去的地方。如果没有,你应该告诉用户:
-
页面有一个新位置。
如果没有自动重定向,他们需要点击链接。
他们应该更新他们的书签。
@
ViewBag.Title = "Page Moved";
@section MetaRefresh
<meta http-equiv="refresh" content="5;@ViewBag.DestinationUrl" />
<h2 class="error">Page Moved</h2>
<p>
The page has moved. Click on the following URL if you are
not redirected automatically in 5 seconds. Be sure to update your bookmarks.
</p>
<a href="@ViewBag.DestinationUrl">@ViewBag.DestinationUrl</a>.
<script>
//<!--
setTimeout(function ()
window.location = "@ViewBag.DestinationUrl";
, 5000);
//-->
</script>
用法
首先,您需要向_Layout.cshtml
添加一个部分,以便可以将元刷新添加到页面的头部部分。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>@ViewBag.Title - My ASP.NET MVC Application</title>
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<!-- Add this so the view can update this section -->
@RenderSection("MetaRefresh", required: false)
<meta name="viewport" content="width=device-width" />
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
</head>
<!-- layout code omitted -->
</html>
然后将RedirectAspxRoute
添加到您的路由配置中。
public class RouteConfig
public static void RegisterRoutes(RouteCollection routes)
routes.IgnoreRoute("resource.axd/*pathInfo");
routes.Add(new RedirectAspxPermanentRoute(
new Dictionary<string, object>()
// Old URL on the left, new route values on the right.
@"/about-us.aspx", new controller = "Home", action = "About" ,
@"/contact-us.aspx", new controller = "Home", action = "Contact"
)
);
routes.MapRoute(
name: "Default",
url: "controller/action/id",
defaults: new controller = "Home", action = "Index", id = UrlParameter.Optional
);
【讨论】:
哇 - 非常全面,谢谢。我需要一些时间来消化这个......目标是捕获所有 .aspx 请求,并在同一个控制器中处理它们all,该控制器只检查 URL,然后重定向到新的相应视图(因为整个站点结构不同)。如果没有匹配的视图,则返回友好的 404。这不仅仅是剥离 .aspx 扩展名的情况,因此我将从您的“奖励”代码开始。 @EvilDr - 我更新(更正)了我的答案。 1)有一个错误,它发送一个相对路径作为 301 重定向,它应该是绝对的 2)我修复了它,所以它通过提供一组路由值而不是硬编码 URL 将更加以 MVC 为中心。这样,如果您更改路由表中的 URL,它将自动更改 301 重定向以匹配它,因为它是从路由表生成的。 与 Dictionary 对象中的静态字符串/Home/Contact
相比,您的更新 new controller = "Home", action = "Contact"
有什么优势?由于两者都不是强类型,因此如果控制器/方法名称发生更改,它无论如何都会中断,对吧?
例如,如果您决定将 [Route] 属性添加到您的操作方法之一,则 URL 将自动更改以匹配 [Route] 属性。但是,如果您要更改路由值列表,则需要更新 RedirectAspxPermanentRoute
配置。在 MVC 中,最好将 URL 生成留给路由表,因为这意味着您只在一个地方定义 URL。
确保更新 RedirectAspxPermanentRoute
类 - 构造函数签名以及它如何将 routeValues 传递给控制器。【参考方案2】:
试试这样的:
routes.MapRoute(
name: "ASPXFilesWithFolderPath",
url: "folder/page.aspx",
defaults: new controller = "ASPXFiles", action = "Index", folder=UrlParameter.Optional, page = UrlParameter.Optional
);
routes.MapRoute(
name: "ASPXFiles",
url: "page.aspx",
defaults: new controller = "ASPXFiles", action = "Index", page = UrlParameter.Optional
);
最初我打算建议 HTTPHandler 但 aspx 扩展名默认映射到 IIS 中,因此无法正常工作。这是Jon Galloway's blog的链接
【讨论】:
谢谢。这仅适用于www.sample.com/default.aspx
,但当路径中包含目录时会失败。
对于每个 / 您需要添加另一个参数。 MVC 将斜杠后的每个字符串标记为新参数的一部分。我用其他可能的 url 映射编辑了答案。【参考方案3】:
由于我的情况,我只有几个主页,有 cockamamy 规则,我发现这更容易.. 创建一个“oldaspxcontroller”。所以我可以确定一切都正确映射。
//https://www.oldsite.com/topics/travel/page9.aspx
[HttpGet]
[Route("/topics/topic/pageoldpagenum.aspx")]
public LocalRedirectResult TopicWithPage(string topic, string oldpagenum)
return LocalRedirectPermanent($"/topics/topic?p=oldpagenum");
您可能会注意到我仍然在查询字符串中使用 pagenum.. 我只是觉得它看起来更好.. 喜欢 mysite.com/topics/travel?p=9 我比 mysite.com/topics/travel/page/9 更喜欢。我在 .Net core 3.1 中,它工作得很好,甚至可以识别模式和页码..
【讨论】:
以上是关于ASP.Net MVC 路由捕获所有 *.aspx 请求的主要内容,如果未能解决你的问题,请参考以下文章
如何在 asp.net mvc 3 项目中路由 .aspx 页面?
asp.net mvc 中 要 访问/ Views/Admin/Order/Index.aspx页面 在 路由里该如何设置?