ASP.NET özel hata sayfası - Server.GetLastError () null


112

Uygulamam için oluşturduğum özel bir hata sayfası var:

<customErrors mode="On" defaultRedirect="~/errors/GeneralError.aspx"
/>

Global.asax, Application_Error () içinde, aşağıdaki kod istisna ayrıntılarını almak için çalışır:

  Exception ex = Server.GetLastError();
  if (ex != null)
    {
        if (ex.GetBaseException() != null)
            ex = ex.GetBaseException();
    }

Hata sayfama geldiğimde (~ / errors / GeneralError.aspx.cs), Server.GetLastError () null oluyor

Global.asax.cs yerine Hata Sayfasında istisna ayrıntılarını alabilmemin bir yolu var mı?

Vista / IIS7 üzerinde ASP.NET 3.5


Ayrıca Cassini ile Win7 üzerinde ASP.NET 4.0 için de geçerlidir
Marcel

"<customErrors mode =" RemoteOnly "defaultRedirect =" ~ / errors / GeneralError.aspx "redirectMode =" ResponseRewrite "/>"
ifadesini

Yanıtlar:


137

Web.config kurulumuma daha yakından baktığımda, bu gönderideki yorumlardan biri çok yardımcı oluyor

asp.net 3.5 sp1'de yeni bir parametre redirectMode var

Yani customErrorsbu parametreyi ekleyerek düzeltebiliriz :

<customErrors mode="RemoteOnly" defaultRedirect="~/errors/GeneralError.aspx" redirectMode="ResponseRewrite" />

ResponseRewritemod URL kalır nedenle aynı, bize tarayıcıyı yönlendirme olmadan «Hata Sayfa» yüklemeye izin verir ve önemlisi benim için, özel durum bilgileri kaybolmaz.


4
Bu benim için işe yaramadı. İstisna bilgisi kayboldu. Bunu Application_Error () 'daki oturumda saklar ve hata sayfamın Page_Load () işleyicisinde geri çekerdim.
BrianK

2
Bu, tüm dokümantasyondaki norm olmalıdır. Bu o kadar iyi ki artık eski davranışı desteklemek için bir neden göremiyorum. Durum kodu doğru olduğu sürece, orijinal istek URL'sini olduğu gibi bırakma konusunda herhangi bir sorun olmamalıdır (tarayıcı yönlendirmesi yapmamak). Aslında bu, HTTP'ye göre daha doğrudur çünkü yanıt kodu, paylaşılan bir hata sayfası isteği değil, istenen URL ile ilgilidir. İşaretçi için teşekkürler, bu yeni özelliği kaçırdım!
Tony Wall

Bu, UpdatePanels içindeki kontroller tarafından tetiklenen istisnalarla çalışmaz ; hata sayfası artık görüntülenmeyecektir.
Sam

2
eski bir cevabım bu Güzel bir yanıtını kanıtlamak için
yorumumu eklediği için

38

Tamam, bu gönderiyi buldum: http://msdn.microsoft.com/en-us/library/aa479319.aspx

bu çok açıklayıcı şema ile:

diyagram
(kaynak: microsoft.com )

özünde, bu istisna ayrıntılarına ulaşmak için, bunları daha sonra özel hata sayfamda tekrar kullanmak üzere Global.asax'ta saklamam gerekiyor.

en iyi yol, işin büyük kısmını Global.asax'ta yapmaktır, mantık yerine yararlı içeriği işleyen özel hata sayfaları ile.


18

NailItDown ve Victor'un söylediklerinin bir kombinasyonu. Tercih edilen / en kolay yol, hatayı saklamak ve ardından özel hata sayfanıza yönlendirmek için Global.Asax'ı kullanmaktır.

Global.asax :

    void Application_Error(object sender, EventArgs e) 
{
    // Code that runs when an unhandled error occurs
    Exception ex = Server.GetLastError();
    Application["TheException"] = ex; //store the error for later
    Server.ClearError(); //clear the error so we can continue onwards
    Response.Redirect("~/myErrorPage.aspx"); //direct user to error page
}

Ek olarak, web.config'inizi kurmanız gerekir :

  <system.web>
    <customErrors mode="RemoteOnly" defaultRedirect="~/myErrorPage.aspx">
    </customErrors>
  </system.web>

Ve son olarak, hata sayfanızda sakladığınız istisna dışında ne gerekiyorsa yapın :

protected void Page_Load(object sender, EventArgs e)
{

    // ... do stuff ...
    //we caught an exception in our Global.asax, do stuff with it.
    Exception caughtException = (Exception)Application["TheException"];
    //... do stuff ...
}

35
Uygulamada saklarsanız, sistemin diğer tüm kullanıcıları ne olacak? Oturumda olması gerekmez mi?
BrianK

11
gerçekten, bunu Uygulamada depolamak gerçekten kötü bir yaklaşım ["TheException"]
Junior Mayhé

4
Ayrıca, kullanıcı başına birden çok "sekmeyi" desteklemek istiyorsanız, istisnaya oturum deposunda benzersiz bir anahtar vermek ve ardından hata sayfasına yeniden yönlendirirken bu anahtarı bir sorgu dizesi parametresi olarak dahil etmek isteyebilirsiniz.
Anders Fjeldstad

5
+1 Ancak bunun Application[]küresel bir nesne olduğunu unutmayın. Teorik olarak, ikinci bir sayfanın hatanın üzerine yazdığı bir yarış koşulunuz olabilir. Bununla birlikte, Session[]hata koşullarında her zaman mevcut olmadığından, bunun daha iyi bir seçim olduğunu düşünüyorum.
Andomar

3
İstisnayı depolamak için kullanılan anahtara yeni bir GUID öneki eklemeniz ve GUID'yi bir parametre olarak özel hata sayfasına iletmeniz yeterlidir.
SteveGSD

6

Gibi bir şey kullanmayı deneyin Server.Transfer("~/ErrorPage.aspx");.Application_Error() global.asax.cs yöntemi

Ardından Page_Load(), ErrorPage.aspx.cs içinden aşağıdaki gibi bir şey yapabilirsiniz:Exception exception = Server.GetLastError().GetBaseException();

Server.Transfer() Görünüşe göre istisnayı etrafta dolaşıyor.


Uygulamam bunu böyle yaptı ve hataların% 99'u için oldukça iyi çalıştı. Ancak bugün, işleme aşamasında meydana gelen bir istisna ile karşılaştım. Eğer varsa Server.Transferbir sayfadan sonra yarı işlenmiş, daha sonra sayfanın HTML basitçe zaten kılındığını ne kadar birleştirilmiş transfer. Böylece yarım kırık sayfayla ve ardından bunun altındaki hata sayfasıyla sonuçlanabilir.
Kevin

Bazı nedenlerden dolayı, Server.Transfer () çağrısı sorunlara neden olur ve hata hiç görüntülenmez. Ve bu nedenle, bu yöntemi kullanmanızı önermiyorum. Yukarıda önerildiği gibi web.config satırını kullanmanız yeterlidir (<customErrors mode = "RemoteOnly" defaultRedirect = "~ / errors / GeneralError.aspx" redirectMode = "ResponseRewrite" />) ve sorunsuz çalışıyor
Naresh Mittal

5

Burada birkaç iyi cevap varken, hata sayfalarında sistem istisna mesajlarını göstermenin iyi bir uygulama olmadığını belirtmeliyim (ki bunu yapmak istediğinizi varsayıyorum). Yanlışlıkla yapmak istemediğiniz şeyleri kötü niyetli kullanıcılara ifşa edebilirsiniz. Örneğin Sql Server istisna mesajları çok ayrıntılıdır ve bir hata oluştuğunda veritabanının kullanıcı adı, şifre ve şema bilgilerini verebilir. Bu bilgi bir son kullanıcıya gösterilmemelidir.


1
Benim durumumda, yalnızca arka uç kullanım için istisna bilgisi istedim, ancak bu iyi bir tavsiye.
nailitdown

2
Soruyu cevaplamıyor.
Arne Evertsson

5

İşte benim çözümüm ..

Global.aspx içinde:

void Application_Error(object sender, EventArgs e)
    {
        // Code that runs when an unhandled error occurs

        //direct user to error page 
        Server.Transfer("~/ErrorPages/Oops.aspx"); 
    }

Oops.aspx'de:

protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
            LoadError(Server.GetLastError()); 
    }

    protected void LoadError(Exception objError)
    {
        if (objError != null)
        {
            StringBuilder lasterror = new StringBuilder();

            if (objError.Message != null)
            {
                lasterror.AppendLine("Message:");
                lasterror.AppendLine(objError.Message);
                lasterror.AppendLine();
            }

            if (objError.InnerException != null)
            {
                lasterror.AppendLine("InnerException:");
                lasterror.AppendLine(objError.InnerException.ToString());
                lasterror.AppendLine();
            }

            if (objError.Source != null)
            {
                lasterror.AppendLine("Source:");
                lasterror.AppendLine(objError.Source);
                lasterror.AppendLine();
            }

            if (objError.StackTrace != null)
            {
                lasterror.AppendLine("StackTrace:");
                lasterror.AppendLine(objError.StackTrace);
                lasterror.AppendLine();
            }

            ViewState.Add("LastError", lasterror.ToString());
        }
    }

   protected void btnReportError_Click(object sender, EventArgs e)
    {
        SendEmail();
    }

    public void SendEmail()
    {
        try
        {
            MailMessage msg = new MailMessage("webteam", "webteam");
            StringBuilder body = new StringBuilder();

            body.AppendLine("An unexcepted error has occurred.");
            body.AppendLine();

            body.AppendLine(ViewState["LastError"].ToString());

            msg.Subject = "Error";
            msg.Body = body.ToString();
            msg.IsBodyHtml = false;

            SmtpClient smtp = new SmtpClient("exchangeserver");
            smtp.Send(msg);
        }

        catch (Exception ex)
        {
            lblException.Text = ex.Message;
        }
    }

4

Burada herkesin eksik olduğunu düşündüğüm önemli bir husus, bir yük dengeleme (web çiftliği) senaryosu. Global.asax'ı çalıştıran sunucu, özel hata sayfasını yürütmekle ilgili olan sunucudan farklı olabileceğinden, istisna nesnesini Uygulamada saklamak güvenilir değildir.

Hala bir web grubu yapılandırmasında bu soruna güvenilir bir çözüm ve / veya neden Sunucu ile istisnayı alamadığınıza dair MS'ten iyi bir açıklama arıyorum. Yapabildiğiniz gibi özel hata sayfasındaGetLastError global.asax Application_Error'da.

PS Verileri Uygulama koleksiyonunda önce kilitlemeden ve sonra kilidini açmadan depolamak güvenli değildir.


Bu, yalnızca istemci tarafı yönlendirme yapıyorsanız geçerli olacaktır. Bir sunucu aktarımı yaparken, hepsi tek bir isteğin parçasıdır, bu nedenle application_error -> page_load, sırayla gruptaki bir sunucuda gerçekleşir.
davewas15

2

Bu, aşağıdaki 2 konu ile ilgili, hem GetHtmlErrorMessage hem de Session on Error sayfasını almak istiyorum.

ResponseRewrite'dan sonra oturum boş

RedirectMode = ResponseRewrite iken neden HttpContext.Session boş?

Gereksiz çözümü denedim ve gördüm Server.Transfer() or Response.Redirect()

İlk olarak: web.config dosyasındaki ResponseRewrite'ı kaldırın

Web.config

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

Ardından Global.asax

    void Application_Error(object sender, EventArgs e)
    {
         if(Context.IsCustomErrorEnabled)
         {     
            Exception ex = Server.GetLastError();
            Application["TheException"] = ex; //store the error for later
         }
    }

Ardından errorHandler.aspx.cs

        protected void Page_Load(object sender, EventArgs e)
            {       
                string htmlErrorMessage = string.Empty ;
                Exception ex = (Exception)Application["TheException"];
                string yourSessionValue = HttpContext.Current.Session["YourSessionId"].ToString();

                //continue with ex to get htmlErrorMessage 
                if(ex.GetHtmlErrorMessage() != null){              
                    htmlErrorMessage = ex.GetHtmlErrorMessage();
                }   
                // continue your code
            }

Referanslar için

http://www.developer.com/net/asp/article.php/3299641/ServerTransfer-Vs-ResponseRedirect.htm


2

Benim için çalıştı. MVC 5'te


içinde ~\Global.asax

void Application_Error(object sender, EventArgs e)
{
    FTools.LogException();
    Response.Redirect("/Error");
}


içinde ~\ControllersoluşturunErrorController.cs

using System.Web.Mvc;

namespace MVC_WebApp.Controllers
{
    public class ErrorController : Controller
    {
        // GET: Error
        public ActionResult Index()
        {
            return View("Error");
        }
    }
}


içinde ~\ModelsoluşturunFunctionTools.cs

using System;
using System.Web;

namespace MVC_WebApp.Models
{
    public static class FTools
    {
        private static string _error;
        private static bool _isError;

        public static string GetLastError
        {
            get
            {
                string cashe = _error;
                HttpContext.Current.Server.ClearError();
                _error = null;
                _isError = false;
                return cashe;
            }
        }
        public static bool ThereIsError => _isError;

        public static void LogException()
        {
            Exception exc = HttpContext.Current.Server.GetLastError();
            if (exc == null) return;
            string errLog = "";
            errLog += "**********" + DateTime.Now + "**********\n";
            if (exc.InnerException != null)
            {
                errLog += "Inner Exception Type: ";
                errLog += exc.InnerException.GetType() + "\n";
                errLog += "Inner Exception: ";
                errLog += exc.InnerException.Message + "\n";
                errLog += "Inner Source: ";
                errLog += exc.InnerException.Source + "\n";
                if (exc.InnerException.StackTrace != null)
                {
                    errLog += "\nInner Stack Trace: " + "\n";
                    errLog += exc.InnerException.StackTrace + "\n";
                }
            }
            errLog += "Exception Type: ";
            errLog += exc.GetType().ToString() + "\n";
            errLog += "Exception: " + exc.Message + "\n";
            errLog += "\nStack Trace: " + "\n";
            if (exc.StackTrace != null)
            {
                errLog += exc.StackTrace + "\n";
            }
            _error = errLog;
            _isError = true;
        }
    }
}


içinde ~\ViewsKlasör Oluştur Error ve ~\Views\ErrorOluşturError.cshtml

@using MVC_WebApp.Models
@{
    ViewBag.Title = "Error";
    if (FTools.ThereIsError == false)
    {
        if (Server.GetLastError() != null)
        {
            FTools.LogException();
        }
    }
    if (FTools.ThereIsError == false)
    {
        <br />
        <h1>No Problem!</h1>
    }
    else
    {
        string log = FTools.GetLastError;
        <div>@Html.Raw(log.Replace("\n", "<br />"))</div>
    }
}


Bu adresi girerseniz localhost/Error Sayfayı Hatasız Aç



Ve bir hata oluşursa Hata oluştu

Hataları görüntülemek yerine, değişken 'günlük' veritabanında depolanacak


Kaynak: Microsoft ASP.Net


1

Sanırım burada birkaç seçeneğiniz var.

Oturumdaki son İstisnayı saklayabilir ve özel hata sayfanızdan geri alabilirsiniz; veya Application_error olayındaki özel hata sayfanıza yönlendirebilirsiniz. İkincisini seçerseniz, Server.Transfer yöntemini kullandığınızdan emin olmak istersiniz.

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.