ASP.Net MVC路由捕获所有* .aspx请求

时间:2016-03-22 14:02:00

标签: c# asp.net asp.net-mvc asp.net-mvc-5 asp.net-mvc-routing

必须之前已被询问,但在阅读herehereherehere后,我无法推断相关内容零件使它工作。我正在将旧的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中设置?

3 个答案:

答案 0 :(得分:2)

我正在显示正确的方式在MVC中进行301重定向,因为并非所有浏览器都能正确响应301重定向请求,并且您需要为用户提供继续而不是默认的选项"对象已移动"由ASP.NET生成的页面。

RedirectAspxPermanentRoute

我们构建了一个自定义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

我们设置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响应的视图,所以您可以使其与您网站其余部分的主题相匹配。所以,如果用户在这里结束,那仍然是一个糟糕的经历。

该视图将尝试通过Meta-Refresh通过JavaScript 自动重定向用户。这两个都可以在浏览器中关闭,但用户可能会把它放到应该去的地方。如果没有,您应该告诉用户:

  1. 该页面有一个新位置。
  2. 如果没有自动重定向,他们需要点击链接。
  3. 他们应该更新他们的书签。
  4. @{
        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,它可以很好地工作,甚至可以识别模式和页码。