Halaman kesalahan kustom ASP.NET - Server.GetLastError () adalah null

112

Saya memiliki halaman kesalahan kustom yang disiapkan untuk aplikasi saya:

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

Di Global.asax, Application_Error (), kode berikut berfungsi untuk mendapatkan detail pengecualian:

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

Pada saat saya membuka halaman kesalahan saya (~ / error / GeneralError.aspx.cs), Server.GetLastError () adalah null

Adakah cara agar saya bisa mendapatkan detail pengecualian di Halaman Kesalahan, selain di Global.asax.cs?

ASP.NET 3.5 di Vista / IIS7

nailitdown
sumber
Berlaku juga di ASP.NET 4.0 di Win7 dengan Cassini
Marcel
tambahkan "<customErrors mode =" RemoteOnly "defaultRedirect =" ~ / error / GeneralError.aspx "redirectMode =" ResponseRewrite "/>" sebagai jawaban yang dikonfirmasi
elle0087

Jawaban:

137

Melihat lebih dekat pengaturan web.config saya, salah satu komentar di posting ini sangat membantu

di asp.net 3.5 sp1 ada parameter redirectMode baru

Jadi kita bisa mengubah customErrorsuntuk menambahkan parameter ini:

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

yang ResponseRewritemode memungkinkan kita untuk memuat «Kesalahan Halaman» tanpa mengarahkan browser, sehingga tetap URL yang sama, dan penting bagi saya, informasi pengecualian tidak hilang.

nailitdown
sumber
4
Ini tidak berhasil untuk saya. Info pengecualian hilang. Saya akan menyimpannya dalam sesi di Application_Error () dan menariknya kembali di penangan Page_Load () dari halaman kesalahan saya.
BrianK
2
Itu harus menjadi norma dalam semua dokumentasi. Ini sangat bagus sehingga saya tidak melihat alasan untuk mendukung perilaku lama lagi. Selama kode statusnya benar, seharusnya tidak ada masalah dengan membiarkan URL permintaan asli tetap utuh (tidak melakukan pengalihan browser). Faktanya itu lebih tepat menurut HTTP karena kode respons berhubungan dengan URL yang diminta, bukan permintaan halaman kesalahan bersama. Terima kasih atas penunjuknya. Saya melewatkan fitur baru itu!
Tony Wall
Ini tidak bekerja dengan pengecualian yang dipicu oleh kontrol di dalam UpdatePanels; halaman kesalahan tidak akan lagi ditampilkan.
Sam
2
karena ini adalah jawaban lama menambahkan komentar saya untuk membuktikan ini bagus nilai ResponseRewrite di redirectmode bekerja di Asp.Net 4.5
Sundara Prabu
38

Oke, saya menemukan posting ini: http://msdn.microsoft.com/en-us/library/aa479319.aspx

dengan diagram yang sangat ilustratif ini:

diagram
(sumber: microsoft.com )

intinya, untuk mendapatkan detail pengecualian tersebut, saya perlu menyimpannya sendiri di Global.asax, untuk diambil nanti di halaman kesalahan kustom saya.

tampaknya cara terbaik adalah melakukan sebagian besar pekerjaan di Global.asax, dengan laman kesalahan khusus menangani konten yang bermanfaat daripada logika.

nailitdown
sumber
18

Kombinasi dari apa yang dikatakan NailItDown dan Victor. Cara yang disukai / termudah adalah dengan menggunakan Global.Asax Anda untuk menyimpan kesalahan dan kemudian mengarahkan ulang ke halaman kesalahan kustom Anda.

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
}

Selain itu, Anda perlu menyiapkan web.config Anda :

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

Dan terakhir, lakukan apa pun yang Anda butuhkan dengan pengecualian yang telah Anda simpan di halaman kesalahan Anda :

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 ...
}
rlb.usa
sumber
35
Jika Anda menyimpannya dalam aplikasi, bagaimana dengan semua pengguna sistem lainnya. Bukankah seharusnya dalam sesi?
BrianK
11
memang, itu pendekatan yang sangat buruk menyimpan ini di Aplikasi ["TheException"]
Junior Mayhé
4
Selain itu, jika Anda ingin mendukung beberapa "tab" per pengguna, Anda mungkin ingin memberikan pengecualian kunci unik di penyimpanan sesi dan kemudian menyertakan kunci tersebut sebagai parameter querystring saat mengalihkan ke halaman kesalahan.
Anders Fjeldstad
5
+1 Tetapi ketahuilah bahwa itu Application[]adalah objek global. Secara teoritis Anda bisa mengalami kondisi balapan di mana halaman kedua menimpa kesalahan. Namun, karena Session[]tidak selalu tersedia dalam kondisi kesalahan, saya rasa ini adalah pilihan yang lebih baik.
Andomar
3
Cukup tambahkan awalan GUID baru ke kunci yang digunakan untuk menyimpan pengecualian dan teruskan GUID sebagai parameter ke halaman kesalahan khusus.
SteveGSD
6

Coba gunakan sesuatu seperti Server.Transfer("~/ErrorPage.aspx");dari dalam Application_Error()metode global.asax.cs

Kemudian dari dalam Page_Load()ErrorPage.aspx.cs Anda akan baik-baik saja untuk melakukan sesuatu seperti:Exception exception = Server.GetLastError().GetBaseException();

Server.Transfer() tampaknya menjaga pengecualian tetap ada.


sumber
Beginilah cara aplikasi saya melakukannya, dan bekerja dengan cukup baik untuk 99% kesalahan. Tapi hari ini saya menemukan pengecualian yang terjadi selama langkah rendering. Jika Anda Server.Transfersetelah halaman dirender setengah, maka HTML halaman yang Anda transfer akan digabungkan dengan apa pun yang telah dirender. Jadi Anda mungkin berakhir dengan setengah halaman rusak diikuti oleh halaman kesalahan di bawahnya.
Kevin
Untuk beberapa alasan, panggilan ke Server.Transfer () menyebabkan masalah dan kesalahan tidak ditampilkan sama sekali. Dan karenanya, saya tidak merekomendasikan menggunakan metode ini. Cukup gunakan baris web.config seperti yang disarankan di atas (<customErrors mode = "RemoteOnly" defaultRedirect = "~ / error / GeneralError.aspx" redirectMode = "ResponseRewrite" />) dan berfungsi dengan baik
Naresh Mittal
5

Meskipun ada beberapa jawaban yang bagus di sini, saya harus menunjukkan bahwa bukanlah praktik yang baik untuk menampilkan pesan pengecualian sistem pada halaman kesalahan (yang saya anggap Anda ingin lakukan). Anda mungkin secara tidak sengaja mengungkapkan hal-hal yang tidak ingin Anda lakukan kepada pengguna jahat. Misalnya pesan pengecualian Server Sql sangat bertele-tele dan dapat memberikan informasi nama pengguna, sandi, dan skema database saat terjadi kesalahan. Informasi itu tidak boleh ditampilkan kepada pengguna akhir.

Phil
sumber
1
Dalam kasus saya, saya hanya menginginkan info pengecualian untuk penggunaan back end, tapi itu saran yang bagus.
nailitdown
2
Tidak menjawab pertanyaan itu.
Arne Evertsson
5

Ini solusi saya ..

Di Global.aspx:

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"); 
    }

Di Oops.aspx:

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;
        }
    }
pengguna825345
sumber
4

Salah satu pertimbangan penting yang menurut saya tidak ada di sini adalah skenario load-balancing (web farm). Karena server yang menjalankan global.asax mungkin berbeda dari server yang mengeksekusi laman kesalahan khusus, menyembunyikan objek pengecualian di Aplikasi tidak dapat diandalkan.

Saya masih mencari solusi yang dapat diandalkan untuk masalah ini dalam konfigurasi web farm, dan / atau penjelasan yang baik dari MS tentang mengapa Anda tidak dapat mengambil pengecualian dengan Server.GetLastError di halaman kesalahan khusus seperti Anda bisa di global.asax Application_Error.

PS Tidak aman menyimpan data dalam koleksi Aplikasi tanpa menguncinya terlebih dahulu, lalu membukanya.

Leonard Lobel
sumber
Ini hanya akan terjadi jika Anda melakukan pengalihan sisi klien. Saat melakukan transfer server, itu semua adalah bagian dari satu permintaan, jadi application_error -> page_load semuanya akan terjadi di satu server di farm, secara berurutan.
davewasthere
2

Ini terkait dengan 2 topik di bawah ini, saya ingin mendapatkan GetHtmlErrorMessage dan Session pada halaman Error.

Sesi menjadi nol setelah ResponseRewrite

Mengapa HttpContext.Session null saat redirectMode = ResponseRewrite

Saya mencoba dan melihat solusi yang tidak perlu Server.Transfer() or Response.Redirect()

Pertama: hapus ResponseRewrite di web.config

Web.config

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

Lalu Global.asax

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

Lalu 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
            }

Untuk referensi

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

Bao
sumber
2

Itu berhasil untuk saya. di MVC 5


di ~\Global.asax

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


di ~\ControllersBuatErrorController.cs

using System.Web.Mvc;

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


di ~\ModelsBuatFunctionTools.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;
        }
    }
}


di ~\ViewsBuat Folder Error dan di ~\Views\ErrorBuatError.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>
    }
}


Jika Anda memasukkan alamat ini localhost/Error buka halaman Tanpa Error



Dan jika terjadi kesalahan terjadi kesalahan

Sebagai pengganti untuk menampilkan kesalahan, variabel 'log' disimpan dalam database


Sumber: Microsoft ASP.Net

MRT2017
sumber
1

Saya pikir Anda memiliki beberapa opsi di sini.

Anda bisa menyimpan Pengecualian terakhir di Sesi dan mengambilnya dari halaman kesalahan kustom Anda; atau Anda bisa mengarahkan ulang ke halaman kesalahan kustom Anda dalam acara Application_error. Jika Anda memilih yang terakhir, Anda ingin memastikan Anda menggunakan metode Server.Transfer.

Pemenang
sumber