Trang lỗi tùy chỉnh ASP.NET - Server.GetLastError () là rỗng


112

Tôi có một trang lỗi tùy chỉnh được thiết lập cho ứng dụng của mình:

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

Trong Global.asax, Application_Error (), mã sau hoạt động để lấy chi tiết ngoại lệ:

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

Vào thời điểm tôi truy cập trang lỗi của mình (~ / error / GeneralError.aspx.cs), Server.GetLastError () là rỗng

Có cách nào tôi có thể lấy chi tiết ngoại lệ trên Trang Lỗi, thay vì trong Global.asax.cs không?

ASP.NET 3.5 trên Vista / IIS7


Áp dụng cũng trên ASP.NET 4.0 trên Win7 với Cassini
Marcel

thêm "<customErrors mode =" RemoteOnly "defaultRedirect =" ~ / error / GeneralError.aspx "redirectMode =" ResponseRewrite "/>" làm câu trả lời đã xác nhận
elle0087

Câu trả lời:


137

Xem xét kỹ hơn cách thiết lập web.config của tôi, một trong những nhận xét trong bài đăng này rất hữu ích

trong asp.net 3.5 sp1 có một tham số redirectMode mới

Vì vậy, chúng tôi có thể sửa đổi customErrorsđể thêm thông số này:

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

các ResponseRewritechế độ cho phép chúng ta nạp «Lỗi trang» mà không chuyển hướng trình duyệt, vì vậy việc nghỉ URL giống nhau, và quan trọng đối với tôi, thông tin ngoại lệ không bị mất.


4
Điều này không hiệu quả với tôi. Thông tin ngoại lệ bị mất. Tôi sẽ lưu trữ nó trong phiên trong Application_Error () và kéo nó trở lại trong trình xử lý Page_Load () của trang lỗi của tôi.
BrianK

2
Đó phải là tiêu chuẩn trong tất cả các tài liệu. Điều này quá tốt, tôi thấy không có lý do gì để ủng hộ hành vi cũ nữa. Miễn là mã trạng thái chính xác, sẽ không có vấn đề gì với việc giữ nguyên URL yêu cầu ban đầu (không thực hiện chuyển hướng trình duyệt). Trên thực tế, điều đó đúng hơn theo HTTP vì mã phản hồi liên quan đến URL được yêu cầu, không phải yêu cầu trang lỗi được chia sẻ. Cảm ơn vì con trỏ tôi đã bỏ lỡ tính năng mới đó!
Tony Wall

Điều này không hoạt động với các ngoại lệ được kích hoạt bởi các điều khiển bên trong UpdatePanels; trang lỗi sẽ không còn được hiển thị.
Sam

2
từ một câu trả lời cũ thêm nhận xét của tôi để chứng minh Nice one giá trị ResponseRewrite này trong tác phẩm redirectmode trong Asp.Net 4.5
Sundara Prabu

38

OK, tôi đã tìm thấy bài đăng này: http://msdn.microsoft.com/en-us/library/aa479319.aspx

với sơ đồ minh họa này:

biểu đồ
(nguồn: microsoft.com )

về bản chất, để có được các chi tiết ngoại lệ đó, tôi cần tự lưu trữ chúng trong Global.asax, để truy xuất sau trên trang lỗi tùy chỉnh của mình.

Có vẻ như cách tốt nhất là thực hiện phần lớn công việc trong Global.asax, với các trang lỗi tùy chỉnh xử lý nội dung hữu ích thay vì logic.


18

Một sự kết hợp giữa những gì NailItDown và Victor đã nói. Cách ưu tiên / dễ nhất là sử dụng Global.Asax của bạn để lưu trữ lỗi và sau đó chuyển hướng đến trang lỗi tùy chỉnh của bạn.

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
}

Ngoài ra, bạn cần thiết lập web.config của mình :

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

Và cuối cùng, hãy làm bất cứ điều gì bạn cần với ngoại lệ bạn đã lưu trữ trong trang lỗi của mình :

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
Nếu bạn lưu trữ nó trong ứng dụng, còn tất cả những người dùng khác của hệ thống thì sao. Nó không nên trong phiên?
BrianK

11
trên thực tế, đó là một cách tiếp cận thực sự tồi tệ lưu trữ này vào Application [ "TheException"]
Junior Mayhé

4
Ngoài ra, nếu bạn muốn hỗ trợ nhiều "tab" cho mỗi người dùng, bạn có thể muốn cung cấp cho ngoại lệ một khóa duy nhất trong cửa hàng phiên và sau đó bao gồm khóa đó dưới dạng tham số chuỗi truy vấn khi chuyển hướng đến trang lỗi.
Anders Fjeldstad

5
+1 Nhưng hãy lưu ý rằng đó Application[]là một đối tượng toàn cục. Về mặt lý thuyết, bạn có thể có một điều kiện chạy đua trong đó trang thứ hai ghi đè lỗi. Tuy nhiên, vì Session[]không phải lúc nào cũng có sẵn trong điều kiện lỗi, tôi nghĩ đây là lựa chọn tốt hơn.
Andomar

3
Chỉ cần thêm tiền tố GUID mới vào khóa được sử dụng để lưu trữ ngoại lệ và chuyển GUID dưới dạng tham số đến trang lỗi tùy chỉnh.
SteveGSD

6

Hãy thử sử dụng một cái gì đó như Server.Transfer("~/ErrorPage.aspx");từ trong Application_Error()phương thức global.asax.cs

Sau đó, từ bên trong Page_Load()ErrorPage.aspx.cs, bạn có thể làm điều gì đó như:Exception exception = Server.GetLastError().GetBaseException();

Server.Transfer() dường như giữ ngoại lệ treo xung quanh.


Đây là cách ứng dụng của tôi đã thực hiện và nó hoạt động khá tốt với 99% lỗi. Nhưng hôm nay tôi đã gặp một ngoại lệ xảy ra trong bước kết xuất. Nếu bạn Server.Transfersau khi một trang được hiển thị một nửa, thì HTML của trang bạn chuyển đến chỉ được nối với bất kỳ thứ gì đã được hiển thị. Vì vậy, bạn có thể kết thúc với một nửa trang bị hỏng, theo sau là trang lỗi bên dưới đó.
Kevin

Vì một số lý do, cuộc gọi đến Server.Transfer () gây ra sự cố và lỗi hoàn toàn không hiển thị. Và do đó, tôi không khuyên bạn nên sử dụng phương pháp này. Đơn giản chỉ cần sử dụng dòng web.config như đề xuất ở trên (<customErrors mode = "RemoteOnly" defaultRedirect = "~ / lỗi / GeneralError.aspx" redirectMode = "ResponseRewrite" />) và nó hoạt động tốt
Naresh Mittal

5

Mặc dù có một số câu trả lời tốt ở đây, tôi phải chỉ ra rằng việc hiển thị thông báo ngoại lệ hệ thống trên các trang lỗi là không tốt (đó là điều tôi cho rằng bạn muốn làm). Bạn có thể vô tình tiết lộ những điều bạn không muốn làm như vậy cho những người dùng độc hại. Ví dụ, thông báo ngoại lệ của Sql Server rất dài và có thể cung cấp tên người dùng, mật khẩu và thông tin lược đồ của cơ sở dữ liệu khi xảy ra lỗi. Thông tin đó không được hiển thị cho người dùng cuối.


1
Trong trường hợp của tôi, tôi chỉ muốn có thông tin ngoại lệ để sử dụng lại, nhưng đó là lời khuyên tốt.
nailitdown

2
Không trả lời câu hỏi.
Arne Evertsson

5

Đây là giải pháp của tôi ..

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

Trong 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;
        }
    }

4

Một cân nhắc quan trọng mà tôi nghĩ rằng mọi người đang thiếu ở đây là một kịch bản cân bằng tải (trang trại web). Vì máy chủ đang thực thi global.asax có thể khác với máy chủ thực thi trang lỗi tùy chỉnh, việc lưu trữ đối tượng ngoại lệ trong Ứng dụng là không đáng tin cậy.

Tôi vẫn đang tìm kiếm một giải pháp đáng tin cậy cho vấn đề này trong cấu hình trang web và / hoặc một lời giải thích tốt từ MS về lý do tại sao bạn không thể chọn ngoại lệ với Server. GetLastError trên trang lỗi tùy chỉnh như bạn có thể trong global.asax Application_Error.

PS Không an toàn khi lưu trữ dữ liệu trong Bộ sưu tập ứng dụng mà không khóa trước rồi mở khóa.


Trường hợp này chỉ xảy ra nếu bạn đang thực hiện chuyển hướng phía máy khách. Khi thực hiện chuyển máy chủ, tất cả đều là một phần của một yêu cầu, do đó, application_error -> page_load sẽ diễn ra theo trình tự trên một máy chủ trong trang trại.
davewasthere

2

Điều này liên quan đến 2 chủ đề bên dưới, tôi muốn nhận được cả GetHtmlErrorMessage và Session on trang Error.

Phiên trống sau ResponseRewrite

Tại sao HttpContext.Session lại rỗng khi redirectMode = ResponseRewrite

Tôi đã thử và thấy giải pháp không cần Server.Transfer() or Response.Redirect()

Đầu tiên: xóa ResponseRewrite trong web.config

Web.config

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

Sau đó Global.asax

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

Sau đó, 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
            }

Để tham khảo

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


2

Nó đã làm việc cho tôi. trong MVC 5


trong ~\Global.asax

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


trong ~\ControllersTạoErrorController.cs

using System.Web.Mvc;

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


trong ~\ModelsTạoFunctionTools.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;
        }
    }
}


trong ~\ViewsTạo thư mục Error và trong ~\Views\ErrorTạoError.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>
    }
}


Nếu bạn nhập địa chỉ này localhost/Error mở trang Lỗi Whithout



Và nếu xảy ra lỗi lỗi xảy ra

Có thể thay vì hiển thị lỗi, biến 'nhật ký' sẽ được lưu trữ trong cơ sở dữ liệu


Nguồn: Microsoft ASP.Net


1

Tôi nghĩ bạn có một vài lựa chọn ở đây.

bạn có thể lưu trữ Ngoại lệ cuối cùng trong Phiên và truy xuất nó từ trang lỗi tùy chỉnh của bạn; hoặc bạn chỉ có thể chuyển hướng đến trang lỗi tùy chỉnh của mình trong sự kiện Application_error. Nếu bạn chọn cái sau, bạn muốn đảm bảo rằng bạn sử dụng phương thức Server.Transfer.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.