2016-04-15 10 views
2

Gibt es eine vollständige Lösung, um Fehler wie 404, 500 usw. auf IIS Express und IIS 7.5 wirklich zu behandeln?C# MVC Fehlerbehandlung von IIS Express und IIS 7.5

ich nicht verzählt haben, wie viele Artikel, die ich gelesen habe, in Bezug auf Web.config, custom Ein, Aus, etc. drehen ... oder Kommentierung/uncommenting filters.Add(new HandleErrorAttribute()); vom FilterConfig.cs

Kann jemand bitte überprüfen, was ich Bis jetzt und sagen Sie mir, was die richtige Konfiguration ist, um Serverfehler sowohl auf IIS Express als auch auf IIS 7.5 vollständig zu erfassen, zeigen Sie eine benutzerdefinierte Fehlerseite und nicht die Shared/Error.cshtml an, die anscheinend egal was und Application_Error aufgerufen wird wird ignoriert.

Global.asax.cs

protected void Application_Error(object sender, EventArgs e) 
{ 
    var lastError = Server.GetLastError(); 

    Server.ClearError(); 

    var statusCode = lastError.GetType() == typeof(HttpException) ? ((HttpException)lastError).GetHttpCode() : 500; 

    var httpContextWrapper = new HttpContextWrapper(Context); 

    var routeData = new RouteData(); 
    routeData.Values.Add("controller", "Error"); 
    routeData.Values.Add("action", "Index"); 
    routeData.Values.Add("statusCode", statusCode); 
    routeData.Values.Add("exception", lastError); 

    IController errorController = new ErrorController(); 

    var requestContext = new RequestContext(httpContextWrapper, routeData); 

    errorController.Execute(requestContext); 

    Response.End(); 
} 

ErrorController.cs

public class ErrorController : Controller 
{ 
    private readonly Common _cf = new Common(); 
    private readonly string _httpReferer = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_REFERER"]; 
    private readonly string _httpUserAgent = System.Web.HttpContext.Current.Request.ServerVariables["HTTP_USER_AGENT"]; 

    public ActionResult Index(int? statusCode, Exception exception) 
    { 
     Response.TrySkipIisCustomErrors = true; 

     try 
     { 
      Response.StatusCode = ((HttpException) exception).GetHttpCode(); 
     } 
     catch (Exception tryException) 
     { 
      SendEmail(tryException, statusCode.ToString()); 

      return Redirect("/"); 
     } 

     SendEmail(exception, Convert.ToString(Response.StatusCode)); 

     ViewBag.Title = statusCode == 404 ? "Page Not Found" : "Server Error"; 

     ViewBag.ExceptionMessage = Convert.ToString(exception.Message); 

     return View("Index"); 
    } 

    private void SendEmail(Exception exception, string errorType) 
    { 
     const string to = "[email protected]"; 
     const string @from = "[email protected]"; 

     var subject = "SendEmailError (" + errorType + ")"; 

     var stringBuilder = new StringBuilder();    
     stringBuilder.Append("<p><strong>Exception Message: </strong>" + exception.Message + "</p>"); 
     stringBuilder.Append("<p><strong>Source: </strong>" + exception.Source + "</p>"); 
     stringBuilder.Append("<p><strong>Referer: </strong>" + _httpReferer + "</p>"); 
     stringBuilder.Append("<p><strong>IP Address: </strong>" + _cf.GetIpAddress() + "</p>"); 
     stringBuilder.Append("<p><strong>Browser: </strong>" + _httpUserAgent + "</p>"); 
     stringBuilder.Append("<p><strong>Target: </strong>" + exception.TargetSite + "</p>"); 
     stringBuilder.Append("<p><strong>Stack Trace: </strong>" + exception.StackTrace + "</p>"); 
     stringBuilder.Append("<p><strong>Inner Exception: </strong>" + (exception.InnerException != null ? exception.InnerException.Message : "") + "</p>"); 

     var body = stringBuilder.ToString(); 

     _cf.SendEmail(subject, to, from, body, null, true, null, null); 
    } 
} 

Index.cshtml

@model WebApplication1.Models.Error 

@if (HttpContext.Current.IsDebuggingEnabled) 
{ 
    if (Model != null) 
    { 
     <p><strong>Exception:</strong> @Model.Exception.Message</p> 
     <div style="overflow:scroll"> 
      <pre>@Model.Exception.StackTrace</pre> 
     </div> 
    } 
    else 
    { 
     <p><strong>Exception:</strong> @ViewBag.ExceptionMessage</p> 
    } 
} 

Error.cs

using System; 

namespace WebApplication1.Models 
{ 
    public class Error 
    { 
     public int HttpStatusCode { get; set; } 

     public Exception Exception { get; set; } 
    } 
} 

Jede Hilfe viel :-)

Antwort

1

hatte nur einen Blick durch ein Projekt geschätzt würde ich vor kurzem tat. Ich habe nur eine Zeile in Application_Error(), welche ist:

Exception ex = Server.GetLastError(); 

FilterConfig.cs

public class FilterConfig 
{ 
    public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
    { 
     //filters.Add(new HandleErrorAttribute()); // Removed because ELMAH reports "cannot find Shared/Error" view instead of the exception. 
    } 
} 

ErrorPageController.cs

public ActionResult DisplayError(int id) 
    { 
     if (id == 404) 
     { 
     //... you get the idea 

Web.config

<customErrors mode="On" defaultRedirect="~/ErrorPage/DisplayError/500"> 
    <error redirect="~/ErrorPage/DisplayError/403" statusCode="403" /> 
    <error redirect="~/ErrorPage/DisplayError/404" statusCode="404" /> 
    <error redirect="~/ErrorPage/DisplayError/500" statusCode="500" /> 
</customErrors> 

und auf der ganzen Unterseite ich diese, mit einem praktischen Kommentar mich daran zu erinnern :)

<system.webServer> 
    <handlers> 
    <add name="ELMAH" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" preCondition="integratedMode" /> 
    </handlers> 
    <httpErrors existingResponse="PassThrough" /> <!-- Required for IIS7 to know to serve up the custom error page --> 
</system.webServer> 
+0

Ich aktualisiere dies nur, aber bitte versuchen Sie, diese Zeile zuerst kommentieren ... okay, mit nur diesen einfachen Änderungen, funktioniert es für Sie? – VictorySaber

+0

Danke, ich habe das HandleErrorAttribute auskommentiert und meinem webconfig ' 'aber immer noch keine Freude, den ErrorController überhaupt nicht zu treffen. – iggyweb

+0

Versuchen Sie, das PassThrough zum webconfig hinzuzufügen – VictorySaber

0

Wie ich weiter vertieft und weiter, dachte ich den Grund für meine spezielle Frage aus. Ich hatte eine Route, die mich störte.

routes.MapRoute("Pages", "{mainCategory}/{subCategory}/{pageName}", new { controller = "Home", action = "Pages", subCategory = UrlParameter.Optional, pageName = UrlParameter.Optional, QueryStringValueProvider = UrlParameter.Optional }); 

Da die Seite getestet www.mydomain.com/blahblah nicht existieren, es fiel in die Seiten Route in der Datenbank, wenn der Inhalt bestand zu überprüfen und, da es nicht tat, kehrte er ein Null-Modell, das wiederum damit die View("Error"} zurück nicht den Error Controller treffen.

Als Ergebnis habe ich einen BaseController an die HomeController gebunden, die eine override void ExecuteResult enthält, um den Fehler 404 korrekt abzufangen.

HomeController. cs

public class HomeController : BaseController 
{ 
    public ActionResult Pages(string mainCategory, string subCategory, string pageName) 
    { 
     var model = _pageDetailsRepository.GetPageDetails(mainCategory, subCategory, false); 

     if (model == null) 
     { 
      // return View("Error") 
      return HttpNotFound(); 
     } 
    } 
} 

Base

public class BaseController : Controller 
{ 
    protected new HttpNotFoundResult HttpNotFound(string statusDescription = null) 
    { 
     return new HttpNotFoundResult(statusDescription); 
    } 

    protected HttpUnauthorizedResult HttpUnauthorized(string statusDescription = null) 
    { 
     return new HttpUnauthorizedResult(statusDescription); 
    } 

    protected class HttpNotFoundResult : HttpStatusCodeResult 
    { 
     public HttpNotFoundResult() : this(null) { } 

     public HttpNotFoundResult(string statusDescription) : base(404, statusDescription) { } 
    } 

    protected class HttpUnauthorizedResult : HttpStatusCodeResult 
    { 
     public HttpUnauthorizedResult(string statusDescription) : base(401, statusDescription) { } 
    } 

    protected class HttpStatusCodeResult : ViewResult 
    { 
     public int StatusCode { get; private set; } 
     public string StatusDescription { get; private set; } 

     public HttpStatusCodeResult(int statusCode) : this(statusCode, null) { } 

     public HttpStatusCodeResult(int statusCode, string statusDescription) 
     { 
      StatusCode = statusCode; 
      StatusDescription = statusDescription; 
     } 

     public override void ExecuteResult(ControllerContext context) 
     { 
      if (context == null) 
      { 
       throw new ArgumentNullException("context"); 
      } 

      context.HttpContext.Response.StatusCode = StatusCode; 

      if (StatusDescription != null) 
      { 
       context.HttpContext.Response.StatusDescription = StatusDescription; 
      } 

      ViewName = "Error"; 

      ViewBag.Title = context.HttpContext.Response.StatusDescription; 

      base.ExecuteResult(context); 
     } 
    } 
} 

Die Web.config hat <system.web><customErrors mode="Off" /></system.web> und <system.webServer><httpErrors existingResponse="PassThrough" /></system.webServer> dank VictorySaber da dies gewährleistet, dass IIS 7.5 passiert den Header 404.

+0

Ich bin froh, dass Sie das Problem gelöst haben :) – VictorySaber

+0

Vielen Dank, Ihr Vorschlag von '' hat geholfen :-) – iggyweb