此必须之前已被询问,但在阅读here,here,here和here后,我无法推断相关内容零件使它工作。我正在将旧的Web表单站点修改为MVC,并希望捕获特定的传入HTTP请求,以便我可以发出RedirectPermanent
(以保护我们的Google排名并避免用户因404而离开)。
我需要截取所有以 .aspx 文件扩展名,例如
id
应忽略对MVC路由的请求(只是正常处理)。
这是我到目前为止所做的,除了www.sample.com/default.aspx
www.sample.com/somedir/file.aspx
www.sample.com/somedir/file.aspx?foo=bar
路线永远不会被击中。
ASPXFiles
}
这种类型的路由是否可以在MVC中设置?
答案 0 :(得分:2)
我正在显示正确的方式在MVC中进行301重定向,因为并非所有浏览器都能正确响应301重定向请求,并且您需要为用户提供继续而不是默认的选项"对象已移动"由ASP.NET生成的页面。
我们构建了一个自定义RouteBase
子类,用于检测网址何时以.aspx
结尾,并路由到SystemController
以设置301重定向。它要求您将URL(要匹配的URL)的映射传递给路由值(用于生成MVC URL)。
public class RedirectAspxPermanentRoute : RouteBase
{
private readonly IDictionary<string, object> urlMap;
public RedirectAspxPermanentRoute(IDictionary<string, object> urlMap)
{
if (urlMap == null)
throw new ArgumentNullException("urlMap");
this.urlMap = 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);
}
}
遵循MVC的惯例,并确保将其放在/Views/System/
文件夹中。
因为它是301响应的视图,所以您可以使其与您网站其余部分的主题相匹配。所以,如果用户在这里结束,那仍然是一个糟糕的经历。
该视图将尝试通过Meta-Refresh通过JavaScript 和自动重定向用户。这两个都可以在浏览器中关闭,但用户可能会把它放到应该去的地方。如果没有,您应该告诉用户:
@{
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
中添加一个部分,以便可以将元刷新添加到页面的head部分。
<!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 }
);
}
}
答案 1 :(得分:0)
尝试这样的事情:
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,但默认情况下会在IIS中映射aspx扩展名,因此不起作用。这是指向Jon Galloway's blog
的链接答案 2 :(得分:0)
由于我的处境,我只有几页主页,并且有一些恶名昭著的规则,所以我发现这更容易。创建一个“ oldaspxcontroller”。因此,我可以确定所有内容都正确映射。
//https://www.oldsite.com/topics/travel/page9.aspx
[HttpGet]
[Route("/topics/{topic}/page{oldpagenum}.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,它可以很好地工作,甚至可以识别模式和页码。