Application_Error, customerrors = "On" olduğunda tetiklenmiyor


124

global.asaxDosyanın Application_Errorolayında, bir hata oluştuğunda yürütülen ve hatanın ayrıntılarını kendime e-postayla gönderen kodum var .

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

    if (error.Message != "Not Found")
    {
        // Send email here...
    }

}

Bu, onu Visual Studio'da çalıştırdığımda iyi çalışıyor, ancak canlı sunucumuzda yayınladığımda Application_Errorolay tetiklenmiyor.

Bazı testlerden sonra , Application_Errorayarladığımda ateşlemeyi alabilirim customErrors="Off", ancak customErrors="On"olayın tekrar ateşlenmesini durduracak şekilde tekrar ayarlayabilirim .

Etkinleştirildiğinde neden Application_Errorateşlenmeyeceğini kimse önerebilir mi?customErrorsweb.config


Ben de aynı sorunu yaşıyorum. Ayrıca şu SO sorusunu buldum: stackoverflow.com/questions/3713939/…, bu da IIS7 sunucusunu klasik moda getirmeyi öneriyor. Maalesef bu bizim için bir seçenek değil. Daha iyi bir çözümü olan var mı?
Jesse Webb

İşte başka bir ilgili soru ve cevapları (hiçbiri kabul edilmiyor) Application_Error () kullanılmamasını öneriyor ... stackoverflow.com/questions/1194578/…
Jesse Webb

@Gweebz Bunu nasıl aştığımla ilgili bir cevap yayınladım, ancak bu davranışı neden aldığıma dair sağlam bir belge bulamadım.
WDuffy

Application_Error()Yöntemin neden kullanılmadığını açıklayan bir cevap ekledim . Ayrıca nihai çözümümü de açıkladım.
Jesse Webb

Gerçekten tavsiye ederim Özel hataların çalışmasını sağlamak için bu makaleyi .
ThomasArdal

Yanıtlar:


133

GÜNCELLEME
Bu yanıt bir çözüm sağladığından, onu düzenlemeyeceğim, ancak bu sorunu çözmenin çok daha temiz bir yolunu buldum. Ayrıntılar için diğer cevabıma bakın ...

Orijinal Cevap: Yöntemin
neden kullanılmadığını anladım Application_Error()...

Global.asax.cs

public class MvcApplication : System.Web.HttpApplication
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute()); // this line is the culprit
    }
...
}

Varsayılan olarak (yeni bir proje oluşturulduğunda), bir MVC uygulamasının Global.asax.cs dosyada . Bu mantık, yolları haritalamak ve filtreleri kaydetmek için kullanılır. Varsayılan olarak, yalnızca bir filtre kaydeder: bir HandleErrorAttributefiltre. CustomErrors açık olduğunda (veya RemoteOnly olarak ayarlandığında uzak istekler aracılığıyla), HandleErrorAttribute, MVC'ye bir Hata görünümü aramasını söyler ve Application_Error()yöntemi asla çağırmaz . Bunun belgesini bulamadım, ancak programmers.stackexchange.com adresindeki bu yanıtta açıklandı .

İşlenmemiş her istisna için çağrılan ApplicationError () yöntemini almak için , HandleErrorAttribute filtresini kaydeden satırı basitçe kaldırın.

Şimdi sorun şu: CustomErrors istediğiniz şeyi elde etmek için nasıl yapılandırılır ...

CustomErrors bölümü varsayılan olarak redirectMode="ResponseRedirect". DefaultRedirect özniteliğini de bir MVC yolu olarak belirtebilirsiniz. Çok basit bir ErrorController oluşturdum ve web.config'imi böyle görünecek şekilde değiştirdim ...

web.config

<customErrors mode="RemoteOnly" redirectMode="ResponseRedirect" defaultRedirect="~/Error">
  <error statusCode="404" redirect="~/Error/PageNotFound" />
</customErrors>

Bu çözümle ilgili sorun, hata URL'lerinize 302 yönlendirmesi yapması ve ardından bu sayfaların bir 200 durum kodu ile yanıt vermesidir. Bu, Google'ın kötü olan hata sayfalarını indekslemesine yol açar. Ayrıca HTTP spesifikasyonuna çok da uygun değildir. Yapmak istediğim şey yeniden yönlendirmemek ve özel hata görünümlerimle orijinal yanıtın üzerine yazmaktı.

Değiştirmeye çalıştım redirectMode="ResponseRewrite". Ne yazık ki, bu seçenek MVC yollarını desteklemez , yalnızca statik HTML sayfalarını veya ASPX'i destekler. İlk başta statik bir HTML sayfası kullanmayı denedim, ancak yanıt kodu hala 200'dü ama en azından yönlendirme yapmadı. Daha sonra bu cevaptan bir fikir edindim ...

Hata işleme için MVC'den vazgeçmeye karar verdim. Bir Error.aspxve bir oluşturdum PageNotFound.aspx. Bu sayfalar çok basitti ama bir parça sihir vardı ...

<script type="text/C#" runat="server">
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        Response.StatusCode = (int) System.Net.HttpStatusCode.InternalServerError;
    }
</script>

Bu blok, sayfaya doğru durum kodunun sunulmasını söyler. Kaba, PageNotFound.aspx sayfasında HttpStatusCode.NotFoundbunun yerine kullandım . Web.config dosyamı böyle görünecek şekilde değiştirdim ...

<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite" defaultRedirect="~/Error.aspx">
  <error statusCode="404" redirect="~/PageNotFound.aspx" />
</customErrors>

Hepsi mükemmel çalıştı!

Özet:

  • Satırı kaldırın: filters.Add(new HandleErrorAttribute());
  • Application_Error()İstisnaları günlüğe kaydetmek için yöntemi kullanın
  • Bir ResponseRewrite ile customErrors kullanın, ASPX sayfalarına işaret edin
  • ASPX sayfalarını kendi yanıt durum kodlarından sorumlu hale getirin

Bu çözümle fark ettiğim birkaç dezavantaj var.

  • ASPX sayfaları, Razor şablonlarıyla herhangi bir biçimlendirmeyi paylaşamaz, tutarlı bir görünüm ve his için web sitemizin standart üstbilgi ve altbilgi biçimlendirmesini yeniden yazmak zorunda kaldım.
  • * .Aspx sayfalarına, URL'lerine tıklanarak doğrudan erişilebilir

Bu sorunlar için geçici çözümler var ama ben fazladan iş yapmak için yeterince endişelenmedim.

Umarım bu herkese yardımcı olur!


2
1! Gerçekten iyi bir çözüm ama MVC'yi aspx sayfalarıyla karıştırmanın sonuçları ne olabilir?
Diego

2
Bunu PROD'da birkaç aydır yapıyoruz ve olumsuz bir etki bulamadım. Tek 'anladığımız', CI'mızı değiştirmemiz ve bir AspCompile MSBUILD görevi yapmak için konuşlandırmamız gerektiğiydi çünkü MVC buna ihtiyaç duymuyor, ancak .as dosyalarını eklediğimizde, buna ihtiyaç duyuyorlardı . Başka sorunlar olabilir ama henüz ortaya çıkmamışlar ...
Jesse Webb

Bu yaklaşımı MVC4'te kullanmaya çalışıyorum ve görünüşe göre benim için sadece aldığımda işe yarıyor <customErrors mode="Off" />. filters.Add(new HandleErrorAttribute());Kaldırılmış ya da kaldırılmış olmanın hiçbir etkisi yoktur.
Grzegorz Sławecki

aspx sayfasında, göstermek istediğiniz görünümü aramak için bir ajax çağrısı ekleyebilirsiniz. Kodu kopyalamak zorunda kalmadan
Mike

71

Bunu bir ExceptionFilter oluşturarak ve Application_Error yerine hatayı orada günlüğe kaydederek çözdüm. Tek yapmanız gereken RegisterGlobalFilters'a bir çağrı eklemek

log4netExceptionFilter.cs

using System
using System.Web.Mvc;

public class log4netExceptionFilter : IExceptionFilter
{
    public void OnException(ExceptionContext context)
    {
        Exception ex = context.Exception;
        if (!(ex is HttpException)) //ignore "file not found"
        {
            //Log error here
        }
    }
}

Global.asax.cs

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new log4netExceptionFilter()); //must be before HandleErrorAttribute
    filters.Add(new HandleErrorAttribute());
}

6
+1 Eğer bu cevap işe yararsa, hataların üstesinden gelmenin en zarif ve belki de amaçlanan yolu (MVC çerçevesine göre) bana öyle geliyor.
Matt Hamsmith 01

2
Bu benim için mükemmel çalışıyor ve burada kabul edilen cevaptan çok daha düzgün. Güzel!
Alex Warren

3
Bu, istisnaları günlüğe kaydetme sorununu çözmek için çalışacaktır. Bunu özel hata sayfalarını göstermeyle nasıl birleştirdiniz?
Jesse Webb

3
Bunu denedim ve 404'ler dışında iyi çalıştı. 404'ler için, Errors.cshtml görünümünü göstermez, yalnızca bana bir YSoD verir. Özel 404'ler gerekli değilse, bu çözüm kesinlikle daha temizdir!
Jesse Webb 05

1
Bunu sevdim. 'CustomErrors = On' ile çalışır
Illidan

36

Bir MVC3 web uygulamasında, istisnaları günlüğe kaydetme yeteneğini engellemeyen özel hata sayfaları oluşturmanın çok daha temiz bir yolunu açıklayan bir makale buldum .

Çözüm, bölümün <httpErrors>elemanını kullanmaktır <system.webServer>.

Web.config yapılandırmamı şöyle yapılandırdım ...

<httpErrors errorMode="DetailedLocalOnly" existingResponse="Replace">
  <remove statusCode="404" subStatusCode="-1" />
  <remove statusCode="500" subStatusCode="-1" />
  <error statusCode="404" path="/Error/NotFound" responseMode="ExecuteURL" />
  <error statusCode="500" path="/Error" responseMode="ExecuteURL" />
</httpErrors>

Ayrıca customErrorssahip olacak şekilde yapılandırdım mode="Off"(makalede önerildiği gibi).

Bu, yanıtların Hata Denetleyicisinin eylemleri tarafından geçersiz kılınmasını sağlar. İşte o denetleyici:

public class ErrorController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult NotFound()
    {
        return View();
    }
}

Görünümler çok açık, sayfaları oluşturmak için standart Razor sözdizimini kullandım.

Bu tek başına MVC ile özel hata sayfalarını kullanmanız için yeterli olacaktır.

Ayrıca, Özel Durumların günlüğe kaydedilmesine de ihtiyacım vardı, bu yüzden Mark'ın özel bir ExceptionFilter kullanma çözümünü çaldım ...

public class ExceptionPublisherExceptionFilter : IExceptionFilter
{
    public void OnException(ExceptionContext exceptionContext)
    {
        var exception = exceptionContext.Exception;
        var request = exceptionContext.HttpContext.Request;
        // log stuff
    }
}

Yapmanız gereken son şey, İstisna Filtresini Global.asax.cs dosyanıza kaydetmektir :

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

Bu, önceki cevabımdan çok daha temiz bir çözüm gibi geliyor ve söyleyebileceğim kadarıyla işe yarıyor. Özellikle MVC çerçevesine karşı mücadele ediyormuş gibi hissetmediğim için hoşuma gitti; bu çözüm aslında onu kullanıyor!


6
Bu çözümün yalnızca IIS 7 ve daha yeni sürümlerde çalıştığını düşündüğümü belirtmekte fayda var; httpErrors öğesi daha yeni eklendi.
Jesse Webb

Bu cevap benim için işe yaramadı, bana sahip, bana korkunç bir mavi oyun: HTTP Error 500.0 - Internal Server Error The page cannot be displayed because an internal server error has occurred. Hata ekranı, istediğim /Error/Indexsayfa değil
Serj Sagan

@SerjSagan Adımları test etmek için bunu yeni bir projede denedim ve iyi çalışıyor. IIS, IIS Express veya VS Dev Server kullanıyor musunuz? Bu VS Dev Server'da çalışmayacaktır. Projemi IIS değil VS Dev Server kullanacak şekilde ayarladığımda, özel hata sayfaları yerine Sarı ekran hataları fark ettim.
Jesse Webb

1
@SerjSagan Ancak klasik Sarı ekran hatalarının aksine, IIS Mavi ekran hataları alıyorsunuz gibi görünüyor. Bu, bir çeşit IIS kullandığınızı varsaymamı sağlıyor. Öyleyse, ilk cümlede bağlantı kurduğum makaleyi, özellikle de "Birkaç önemli not" başlıklı son bölümü okuyun. Diyor ki:To able to overwrite global settings in global IIS settings (file: C:\Windows\System32\inetsrv\config \applicationHost.config) should be: <section name="httpErrors" overrideModeDefault="Allow" />
Jesse Webb

3
@SerjSagan errorMode'u DetailedLocalOnly veya Custom olarak değiştirmek sayfanızı gösterecektir.
Daniel P

8

ASP.NET MVC5 kullanılması durumunda

public class ExceptionPublisherExceptionFilter : IExceptionFilter
    {
        private static Logger _logger = LogManager.GetCurrentClassLogger();
        public void OnException(ExceptionContext exceptionContext)
        {
            var exception = exceptionContext.Exception;
            var request = exceptionContext.HttpContext.Request;
            // HttpException httpException = exception as HttpException;
            // Log this exception with your logger
            _logger.Error(exception.Message);
        }
    }

Sen de bulabilirsiniz FilterConfig.csait App_Startklasörde.


1

Mark'ın ExceptionFilter ile cevabını beğendim, ancak diğer bir seçenek, tüm denetleyicilerinizin aynı temel denetleyiciden türetilmesi durumunda, temel denetleyicinizde OnException'ı basitçe geçersiz kılmaktır. Kayıt ve e-posta göndermenizi orada yapabilirsiniz. Bu, IoC konteynırınızla temel kontrol cihazınıza zaten enjekte ettiğiniz bağımlılıkları kullanabilme avantajına sahiptir.

Yine de IoC'nizi bir IExceptionFilter ile kullanabilirsiniz, ancak bağlamalarınızı yapılandırmak biraz daha zor.


0

Bildiğim kadarıyla, kontrolü url parametresinde belirtilen Sayfaya aktarıyorsunuz ve etkinlik bildiriminiz Application_Error yerine burada yer alacak.

<customErrors defaultRedirect="myErrorPage.aspx"
              mode="On">
</customErrors>

Burada birçok bilgi bulunabilir: http://support.microsoft.com/kb/306355


Teşekkürler Chris, belgeleri okudum ve Application_Error'ın işlenmemiş bir hata oluştuğunda çağrılacağını (beklediğim gibi) ve bunun da Server.ClearError () web.config customErrors bölümü olarak adlandırılmaması gerektiğini öneriyor. Bununla birlikte, customError'ın etkinleştirilmesi, Application_Error'ın etkinleşmesini durduran şeydir.
WDuffy

Bağlandığınız belgeler ASP.NET uygulaması hakkında konuşuyor ve MVC3 web uygulamalarının farklı davrandığı görülüyor.
Jesse Webb

0

Bunu aşmak için müşteri hatalarını devre dışı bıraktım ve global.asax içindeki Application_Error olayındaki tüm hataları ele aldım. 301 yönlendirmesini döndürmek istemediğim için MVC ile biraz zor, uygun hata kodlarını döndürmek istedim. Blogumda daha fazla ayrıntı http://www.wduffy.co.uk/blog/using-application_error-in-asp-net-mvcs-global-asax-to-handle-errors/ adresinde görüntülenebilir ancak son kod aşağıda listelenmiş...

void Application_Error(object sender, EventArgs e)
{
    var error = Server.GetLastError();
    var code = (error is HttpException) ? (error as HttpException).GetHttpCode() : 500;

    if (code != 404)
    {
            // Generate email with error details and send to administrator
    }

    Response.Clear();
    Server.ClearError();

    string path = Request.Path;
    Context.RewritePath(string.Format("~/Errors/Http{0}", code), false);
    IHttpHandler httpHandler = new MvcHttpHandler();
    httpHandler.ProcessRequest(Context);
    Context.RewritePath(path, false);
}

Ve işte kontrolör

public class ErrorsController : Controller
{

    [HttpGet]
    public ActionResult Http404(string source)
    {
            Response.StatusCode = 404;
            return View();
    }

    [HttpGet]
    public ActionResult Http500(string source)
    {
            Response.StatusCode = 500;
            return View();
    }

}

Çözümünüzü denedim ama benim için işe yaramadı. Satırlarla birlikte, Response.StatusCode = ###;yerleşik MVC hata sayfalarını C:\inetpub\custerr\en-US. HttpHandlers veya Controllers'ı Application_Error () yöntemimden manuel olarak çağırma fikrini de beğenmedim. Sorununuza bir çözüm bulduğunuza sevindim, bunun bana ne tür baş ağrıları verdiğini biliyorum.
Jesse Webb

0

Bu blog girişi bana yardımcı oldu:

http://asp-net.vexedlogic.com/2011/04/23/asp-net-maximum-request-length-exceeded/

IIS 7.0 veya üstünü kullanıyorsanız, Web.config dosyanızı çok büyük istekleri işleyecek şekilde değiştirebilirsiniz. Bazı uyarılar var, ancak işte bir örnek:

<system.webServer>
  <security>
    <requestFiltering>
      <requestLimits maxAllowedContentLength="1048576" />
    </requestFiltering>
  </security>
  <httpErrors errorMode="Custom" existingResponse="Replace">
    <remove statusCode="404" subStatusCode="13" />
    <error statusCode="404" subStatusCode="13" prefixLanguageFilePath="" path="/UploadTooLarge.htm" responseMode="Redirect" />
  </httpErrors>
</system.webServer>

Bu yapılandırma dosyası öğeleriyle ilgili ek ayrıntılar burada:

http://www.iis.net/ConfigReference/system.webServer/security/requestFiltering/requestLimits

Durum kodu 404.13, "İçerik Uzunluğu Çok Uzun" olarak tanımlandı. Unutulmaması gereken önemli bir nokta, maxAllowedContentLengthbayt cinsinden belirtilmesidir. Bu, kilobayt cinsinden belirtilen bölümde maxRequestLengthbulduğunuz ayardan farklıdır <system.web>.

<system.web>
  <httpRuntime maxRequestLength="10240" />
</system.web>

Ayrıca unutmayınız pathzaman nitelik mutlak yol olmalıdır responseModeolup Redirect, ilgili eğer öyleyse, sanal dizin adını prepend. Jesse Webb'in bilgilendirici cevapları bunun nasıl yapılacağını gösteriyor responseMode="ExecuteURL"ve bu yaklaşımın da işe yarayacağını düşünüyorum.

Visual Studio Geliştirme Sunucusu (Cassini, Visual Studio ile tümleşik Web sunucusu) kullanarak geliştirme yapıyorsanız bu yaklaşım işe yaramaz. IIS Express'te çalışacağını varsayıyorum, ancak bunu test etmedim.


0

Vurulmayan yerde aynı sorunu yaşıyordum Application_Error(). Her şeyi denedim, sonunda neler olup bittiğine adım atana kadar. Bir ELMAH etkinliğinde, gönderdiği e-postaya JSON ekleyen bazı özel kodum vardı ve orada boş bir hata vardı!

Dahili hatanın düzeltilmesi, kodun Application_Error()beklendiği gibi olaya devam etmesine izin verdi .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.