如何重定向所有与控制器无关的 url(Asp.Net MVC)



如果有人将类似www.example/bla/qwerty.hm(它没有控制器且不存在(的东西放在www.example.com,我想总是重定向到我的主页。

我想将所有没有控制器的 url 重定向到我的主页并且不显示错误。例如:www.example.com/auto(auto 不是控制器(,它将被重定向到我的主页。我该怎么做?

  1. 我尝试了路由配置

    routes.MapRoute(
    name: "MyRedirect"
    , url: "{contextRedirect}/{*tasks}"
    , defaults: new { controller = "Redirect", action = "TotalRedirect", contextRedirect = "" }
    );
    

    public ActionResult TotalRedirect(string contextRedirect)
    {
    return RedirectToAction("Index", "Home");
    }
    

但是每次都会调用它,并且它会产生一个无限循环(每次调用重定向到操作时都会调用它(

如果我在此MapRoute之前为所有现有控制器编写所有RouteMaps,则问题消失了,但是我有很多控制器,我想避免为所有控制器编写RouteMaps

  1. 而不是MapRoute,我尝试了Web.config并更改了错误

    <customErrors mode="On">
    <error redirect="/Error" statusCode="404" />
    <error redirect="/Error" statusCode="500" />
    </customErrors>
    

    错误是返回RedirectToAction的控制器,我得到了与点 1(无限循环(相同的结果。但是当我/Error更改为/Home时,它正在工作(因为主页返回视图(,但在 URL 路径上保存了错误文本Home?aspxerrorpath=/auto.重定向后我不想显示文本,这意味着如果页面将被重定向到www.example.com,它不会显示www.example/Home?aspxerrorpath=/auto

我是 Asp.net MVC的新手,我不知道如何做到这一点。


更新

经过一些研究,我认为有两种方法可以做到这一点。

  1. (感謝 KevinLamb( 從 error with Application_Error and Web.Confing httpError 重定向。这对我有用:

    此设置放在项目级别的 Web.Confing 中,这意味着您在项目资源管理器中看到的第一个 Web.Config(View 文件夹中有第二个 Web.Config(。然后,必须使用操作结果错误句柄创建名为"错误"的控制器

    <system.webServer>
    <httpErrors errorMode="Custom" existingResponse="Replace">
    <remove statusCode="404"/>
    <error statusCode="404" responseMode="ExecuteURL" path="/Error/ErrorHandle"/>
    <remove statusCode="400"/>
    <error statusCode="400" responseMode="ExecuteURL" path="/Error/ErrorHandle"/>
    <remove statusCode="500"/>
    <error statusCode="500" responseMode="ExecuteURL" path="/Error/ErrorHandle"/>
    </httpErrors>
    

    // Error Controller .cs
    namespace MyWebApp.Controllers
    {
    public class ErrorController : Controller
    {
    // GET: Error
    public ActionResult Index()
    {
    return RedirectToAction("Home", "Index");
    }
    public ActionResult ErrorHandle()
    {
    return RedirectToAction("Index", "Home");
    }
    }
    }
    

    // code inside Global.asax.cs MvcApplication class
    protected void Application_Error(object sender, EventArgs e)
    {
    Exception ex = Server.GetLastError();
    //Add some logging here
    if(ex.GetType().IsAssignableFrom(typeof(HttpException)))
    {
    //Possibly log that you're redirecting the user
    Response.Clear();
    Response.Redirect("~/");
    }
    }
    

    这是容易的部分。


  1. 我发现的另一种方法是创建 HttpHandler 或 HttpModule。我是MVC和 Asp.Net 世界的新手,HttpHandler对我来说并不完全有效,因为它只工作一次,然后仅在应用程序更改页面时工作,但它不会检测到用户创建的URL(只有第一次(。HttpModule 对我来说一直有效,但我不知道它是好是坏。它比 1 难一点。点,但你不需要 Web.config 中的 Application_Error 和 httpErrors。

    如果您有 httpError 和Application_Error,请将其删除并创建模块(右键单击Project > Add new Item > In search put "module" > and select Asp.Net Module.它使用InitDispose方法创建模块类。然后创建自己的方法并将其注册到BeginRequest

这是我的 HttpModule 的代码

using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Reflection;
using System.Linq;
namespace MyWebApp
{
public class ErrorHttpModule : IHttpModule
{
#region IHttpModule Members
public void Dispose()
{
//clean-up code here.
}
public void Init(HttpApplication context)
{
// Below is an example of how you can handle LogRequest event and provide 
// custom logging implementation for it
// context.LogRequest += new EventHandler(OnLogRequest);
context.BeginRequest += new EventHandler(BR); // register your own method in to Event where you check Url
}
#endregion
private HttpContext context = null;
public void BR(Object source, EventArgs e)
{
context = System.Web.HttpContext.Current;
// collect all controllers in web application
Assembly asm = Assembly.GetAssembly(typeof(MyWebApp.MvcApplication)); // need using System.Reflection;
var controlleractionlist = asm.GetTypes()
.Where(type => typeof(System.Web.Mvc.Controller).IsAssignableFrom(type)) // need using System.Linq;
.SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public))
.Where(m => !m.GetCustomAttributes(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), true).Any())
.Select(x => new { Controller = x.DeclaringType.Name, Action = x.Name, ReturnType = x.ReturnType.Name, Attributes = String.Join(",", x.GetCustomAttributes().Select(a => a.GetType().Name.Replace("Attribute", ""))) })
.OrderBy(x => x.Controller).ThenBy(x => x.Action).ToList();

// Get Url
string page = "";
if (context != null)
{
page = context.Request.Url.PathAndQuery;
}
string newUrl;
if (!String.IsNullOrEmpty(page))
{
bool continute = true;
// does url contain controller or action?
foreach (var controller in controlleractionlist)
{
string cpath = "/" + controller.Controller.Replace("Controller", "") + (controller.Action == "Index" ? "" : "/" + controller.Action);
if (cpath == page)
{
// Yes, don't continue to redirect
continute = false;
break;
}
else if (page == ("/" + controller.Action))
{
// Yes, don't continue to redirect
continute = false;
break;
}
}
// does page load your content, script etc.. ?
if (page.Contains("Content/") == true
|| page.Contains("Scripts/") == true
|| page.Contains(".ico") == true
|| page == "/"
)
{
// Yes, don't redirect.
continute = false;
}
if (continute)

{
// anything else will redirect to Home page
var urlHelper = new UrlHelper(context.Request.RequestContext); // nned using System.Web.Mvc;
newUrl = urlHelper.Action("About", "Home");
context.Response.Status = "301 Moved Permanently";
context.Response.AddHeader("Location", newUrl);
context.Response.End();
}
}
}
public void OnLogRequest(Object source, EventArgs e)
{
//custom logging logic can go here
}
}
}

并且最终将模块添加到Web.Config中(在项目级别(ProjectName> Web.Config(,而不是在Project下的文件夹内(ProjectName> View> Web.Config(内(

<system.webServer>
<modules>
<add name="MyHttpErrorModule" type="MyWebApp.ErrorHttpModule, MyWebApp"/>
</modules>
</system.webServer>

扩展问题

无论是第一点还是第二点,我都遇到问题,当在 url 中放置这样的字符时/abc=45%$#r.它会导致Bad Request - Invalid URL HTTP Error 400. The request URL is invalid.,这不会检测到Web.Config中的Application_Error,httpErrors或我的HttpModule with BeginRequest。因此,我认为这是在IIS设置上,但是我需要设置什么?看起来这些字符使IIS变得混乱%$

首先,您需要设置要在 IIS 中传递的错误,以便应用程序可以处理文件/参数链接而不是 IIS。将以下内容添加到您的Web.config

<system.webServer>
<httpErrors existingResponse="PassThrough" />
</system.webServer>

如果要在用户转到错误的控制器/操作时重定向到主页(URL 中没有任何额外参数(,请将以下代码添加到Global.asax.cs

protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
//Add some logging here
if(ex.GetType().IsAssignableFrom(typeof(HttpException)))
{
//Possibly log that you're redirecting the user
Response.Clear();
Response.Redirect("~/");
}
}

基本上,这样做是使您的 ASP.NET MVC网站中的所有错误都通过此方法。然后,它会检查异常是否为HttpException。如果是,它将重定向到您的家庭控制器并执行操作。如果它不是HttpException它将继续执行错误处理过程。这样,您可以继续正确处理重要错误。