错误500而不是404

时间:2015-03-23 15:39:49

标签: c# asp.net asp.net-mvc elmah

我有一个asp.net MVC 5项目,我试图抛出404错误而不是500错误。

错误是

  

公共行动方法'某事物'在控制器上找不到   ' ProjetX.Controllers.HomeController'

  

路径控制器' /某些'未找到或未执行   一个IController

我理解为什么它会出现错误500,但我想抛出404.这对SEO来说会更好。

我无法弄清楚如何

这是我的代码

我的elmah的ExceptionHandler类

public class HandleCustomError : HandleErrorAttribute
    {

        public override void OnException(ExceptionContext filterContext)
        {
            //If the exeption is already handled we do nothing
            if (filterContext.ExceptionHandled)
            {
                return;
            }
            else
            {
                //Log the exception with Elmah
                Log(filterContext);

                Type exceptionType = filterContext.Exception.GetType();

                //If the exception is while an ajax call
                if (exceptionType == typeof(ExceptionForAjax))
                {
                    filterContext.HttpContext.Response.Clear();
                    filterContext.HttpContext.Response.ContentEncoding = Encoding.UTF8;
                    filterContext.HttpContext.Response.HeaderEncoding = Encoding.UTF8;
                    filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
                    filterContext.HttpContext.Response.StatusCode = 500;
                    filterContext.HttpContext.Response.StatusDescription = filterContext.Exception.Message;
                }
                else
                {
                    base.OnException(filterContext);
                }

            }

            //Make sure that we mark the exception as handled
            filterContext.ExceptionHandled = true;
        }

        private void Log(ExceptionContext context)
        {
            // Retrieve the current HttpContext instance for this request.
            HttpContext httpContext = context.HttpContext.ApplicationInstance.Context;

            if (httpContext == null)
            {
                return;
            }

            // Wrap the exception in an HttpUnhandledException so that ELMAH can capture the original error page.
            Exception exceptionToRaise = new HttpUnhandledException(message: null, innerException: context.Exception);

            // Send the exception to ELMAH (for logging, mailing, filtering, etc.).
            ErrorSignal signal = ErrorSignal.FromContext(httpContext);
            signal.Raise(exceptionToRaise, httpContext);
        }

    }

我如何添加自定义错误

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleCustomError());
        }

路线配置

public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute("Robots.txt",
                "robots.txt",
                new { controller = "robot", action = "index" });

            routes.MapRoute(
                name: "Localization",
                url: "{lang}/{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
                constraints: new { lang = @"^[a-zA-Z]{2}$" }

            );

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );

       routes.MapRoute(
        "NotFound",
        "{*url}",
        new { controller = "Error", action = "Error404" }
        );


            routes.MapMvcAttributeRoutes();
        }

我的webconfig

<system.web>
    <authentication mode="None" />
    <compilation debug="true" targetFramework="4.5" />
    <!-- 2MB-->
    <httpRuntime targetFramework="4.5" maxRequestLength="2097152" />
    <httpModules>
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
      <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
      <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
    </httpModules>
    <!-- Set mode to RemoteOnly in production -->
    <customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="/Error/Error500">
      <error statusCode="400" redirect="/Error/Error400" />
      <error statusCode="404" redirect="/Error/Error404" />
      <error statusCode="500" redirect="/Error/Error500" />
    </customErrors>
  </system.web>
  <system.webServer>
    <httpErrors errorMode="Custom" existingResponse="Replace">
      <remove statusCode="400" subStatusCode="-1" />
      <error statusCode="400" path="/Error/Error400" responseMode="ExecuteURL" />
      <remove statusCode="404" subStatusCode="-1" />
      <error statusCode="404" path="/Error/Error404" responseMode="ExecuteURL" />
      <remove statusCode="500" subStatusCode="-1" />
      <error statusCode="500" path="/Error/Error500" responseMode="ExecuteURL" />
    </httpErrors>
    <modules>
      <remove name="FormsAuthenticationModule" />
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
      <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />
      <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
    </modules>
    <validation validateIntegratedModeConfiguration="false" />
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
      <add name="Robots-ISAPI-Integrated-4.0" path="/robots.txt" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
    <staticContent>
    </staticContent>
  </system.webServer>

我想处理HandleCustomError类中的错误,但问题是它直接进入错误控制器中的Error500操作。

奇怪的是,错误仍记录在elmah中。

它没有触及HandleCustomError类中的任何断点,如何记录错误?

谢谢

1 个答案:

答案 0 :(得分:1)

这是最终的代码

我必须添加2个函数来生成一个带有我的控制器和动作名称的正则表达式

public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");


        routes.MapRoute(
            name: "Localization",
            url: "{lang}/{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            constraints: new { lang = @"^[a-zA-Z]{2}$", controller = GetAllControllersAsRegex(), action = GetAllActionsAsRegex }

        );

        routes.MapRoute(
            "Default",
            "{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            new { controller = GetAllControllersAsRegex(), action = GetAllActionsAsRegex() }
        );

        routes.MapRoute(
        "NotFound",
        "{*url}",
        new { controller = "Error", action = "Error404" }
        );

        routes.MapMvcAttributeRoutes();
    }
    private static string GetAllControllersAsRegex() 
    { 
        var controllers = typeof(MvcApplication).Assembly.GetTypes()
            .Where(t => t.IsSubclassOf(typeof(Controller))); 

        var controllerNames = controllers
            .Select(c => c.Name.Replace("Controller", "")); 

        return string.Format("({0})", string.Join("|", controllerNames)); 
    }
    private static string GetAllActionsAsRegex()
    {
        Assembly asm = Assembly.GetExecutingAssembly();

        var actions = asm.GetTypes()
                        .Where(type => typeof(Controller).IsAssignableFrom(type)) //filter controllers
                        .SelectMany(type => type.GetMethods())
                        .Where(method => method.IsPublic && !method.IsDefined(typeof(NonActionAttribute)))
                        .Select(x=>x.Name);

        return string.Format("({0})", string.Join("|", actions)); 
    }
}

另见
https://stackoverflow.com/a/4668252