asp.net-mvc - 如何重定向所有与控制器无关的 url (Asp.Net MVC)
问题描述
www.example/bla/qwerty.hm
如果有人把类似的东西(它没有控制器并且它不存在)放到我想总是重定向到我的主页www.example.com
.
我想将所有没有控制器的 url 重定向到我的主页并且不显示错误。例如:(www.example.com/auto
自动不是控制器)它将被重定向到我的主页。我怎么做?
我尝试了路由配置
routes.MapRoute( name: "MyRedirect" , url: "{contextRedirect}/{*tasks}" , defaults: new { controller = "Redirect", action = "TotalRedirect", contextRedirect = "" } );
...
public ActionResult TotalRedirect(string contextRedirect) { return RedirectToAction("Index", "Home"); }
但是每次都会调用它并且它会产生一个无限循环(每次调用redirectToAction时都会调用它)
RouteMaps
如果我在此之前为所有现有控制器编写所有内容,问题就会消失MapRoute
,但我有很多控制器,我想避免RouteMaps
为所有控制器编写内容。
而不是 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 的新手,我不知道正确的方法。
更新
经过一番研究,我认为有两种方法可以做到这一点。
(感谢 KevinLamb)使用 Application_Error 和 Web.Confing httpError 从错误中重定向。这对我有用:
此设置放在项目级别的 Web.Confing 中,这意味着您在项目资源管理器中看到的第一个 Web.Config(在 View 文件夹中有第二个 Web.Config)。然后您必须使用 ActionResult ErrorHandle 创建名为 Error 的控制器
<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("~/"); } }
这是容易的部分。
我发现的另一种方法是创建 HttpHandler 或 HttpModule。我是 MVC 和 Asp.Net 世界的新手,而 HttpHandler 对我来说并不总是有效,因为它只工作一次,然后只在应用程序更改页面时工作,但它不检测用户创建的 Url(仅第一次)。HttpModule 总是为我工作,但我不知道它是好是坏。它比 1. 难一点,但你不需要 Web.Config 中的 Application_Error 和 httpErrors。
如果您有 httpErrors 和 Application_Error,请将其删除并创建模块(右键单击它使用和方法
Project > Add new Item > In search put "module" > and select Asp.Net Module.
创建模块类。然后创建自己的方法并将其注册到.Init
Dispose
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),而不是在项目下的文件夹内(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 或带有 BeginRequest 的我的 HttpModule。因此我认为这是在 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
,它将继续执行错误处理过程。这样您就可以继续正确处理重要错误。