Error.cshtml được gọi như thế nào trong ASP.NET MVC?


78

Tôi đã đọc hàng tá câu hỏi tương tự trên StackOverflow, nhưng dường như tôi không thể hiểu được điều này. Liên quan đến nút lỗi tùy chỉnh trong web.config và HandleErrorAttribute, làm thế nào để Error.cshtml được gọi? Cuối cùng câu trả lời cho câu hỏi này có thể là câu trả lời cho một trong số những câu hỏi đã có liên quan đến việc xử lý lỗi ASP.NET MVC. Nhưng, thực tế của vấn đề là, tôi không biết cái nào.

Câu trả lời:


91

Bên trong Global.asax của bạn, bạn có phương thức sau:

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

Điều này đăng ký HandleErrorAttribute làm bộ lọc hành động chung. Điều này có nghĩa là trình xử lý này được tự động áp dụng cho tất cả các hành động của bộ điều khiển. Bây giờ chúng ta hãy xem cách thuộc tính này được triển khai bằng cách xem mã nguồn:

[SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "This attribute is AllowMultiple = true and users might want to override behavior.")]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class HandleErrorAttribute : FilterAttribute, IExceptionFilter {

    private const string _defaultView = "Error";

    private readonly object _typeId = new object();

    private Type _exceptionType = typeof(Exception);
    private string _master;
    private string _view;

    public Type ExceptionType {
        get {
            return _exceptionType;
        }
        set {
            if (value == null) {
                throw new ArgumentNullException("value");
            }
            if (!typeof(Exception).IsAssignableFrom(value)) {
                throw new ArgumentException(String.Format(CultureInfo.CurrentCulture,
                    MvcResources.ExceptionViewAttribute_NonExceptionType, value.FullName));
            }

            _exceptionType = value;
        }
    }

    public string Master {
        get {
            return _master ?? String.Empty;
        }
        set {
            _master = value;
        }
    }

    public override object TypeId {
        get {
            return _typeId;
        }
    }

    public string View {
        get {
            return (!String.IsNullOrEmpty(_view)) ? _view : _defaultView;
        }
        set {
            _view = value;
        }
    }

    public virtual void OnException(ExceptionContext filterContext) {
        if (filterContext == null) {
            throw new ArgumentNullException("filterContext");
        }
        if (filterContext.IsChildAction) {
            return;
        }

        // If custom errors are disabled, we need to let the normal ASP.NET exception handler
        // execute so that the user can see useful debugging information.
        if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled) {
            return;
        }

        Exception exception = filterContext.Exception;

        // If this is not an HTTP 500 (for example, if somebody throws an HTTP 404 from an action method),
        // ignore it.
        if (new HttpException(null, exception).GetHttpCode() != 500) {
            return;
        }

        if (!ExceptionType.IsInstanceOfType(exception)) {
            return;
        }

        string controllerName = (string)filterContext.RouteData.Values["controller"];
        string actionName = (string)filterContext.RouteData.Values["action"];
        HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
        filterContext.Result = new ViewResult {
            ViewName = View,
            MasterName = Master,
            ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
            TempData = filterContext.Controller.TempData
        };
        filterContext.ExceptionHandled = true;
        filterContext.HttpContext.Response.Clear();
        filterContext.HttpContext.Response.StatusCode = 500;

        // Certain versions of IIS will sometimes use their own error page when
        // they detect a server error. Setting this property indicates that we
        // want it to try to render ASP.NET MVC's error page instead.
        filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
    }
}

Mã nguồn chứa các bình luận và không chỉ là tự giải thích. Điều đầu tiên nó kiểm tra là bạn đã bật lỗi tùy chỉnh trong web.config của mình (tức là <customErrors mode="On">). Nếu bạn không có nó thì không có gì => YSOD. Nếu bạn đã bật lỗi tùy chỉnh thì chế độ xem Lỗi sẽ chuyển cho nó một mô hình có chứa ngăn xếp ngoại lệ và thông tin hữu ích khác.


Tôi vẫn còn khá mới với ASP.NET MVC, nhưng tôi nghĩ rằng mỗi Chế độ xem phải tương ứng với một số hành động của bộ điều khiển. Bộ điều khiển và hành động ở đây là gì và làm thế nào nó biết để đi đến Chia sẻ cho chế độ xem? Có vẻ như cơ chế này ở đây để ngắt và hoán đổi trong chế độ xem Lỗi.
LJM

3
Có, mỗi chế độ xem phải tương ứng với một hành động của bộ điều khiển. Hành động của bộ điều khiển trong trường hợp này là hành động đang được thực thi và sẽ ném ra một ngoại lệ. Có thể là bất kỳ hành động điều khiển nào. Ngoại lệ này bị chặn bởi bộ lọc hành động chung (trong trường hợp này là bộ lọc ngoại lệ) và hiển thị chế độ xem Lỗi. Vì ngoại lệ được ném bên trong hành động của bộ điều khiển nên hành động này không bao giờ trả lại, nó chỉ đơn giản dừng thực thi ở giai đoạn này và xử lý việc thực thi cho trình xử lý lỗi mà lần lượt nó sẽ hiển thị chế độ xem.
Darin Dimitrov

12
Điều này có thay đổi trong MVC 5.1 không? Đối với tôi, có vẻ như HandleErrorAttribute được đăng ký theo mặc định (mà chúng tôi không cần phải thêm nó vào danh sách bộ lọc trong RegisterGlobalFilters) và chúng tôi không cần kích hoạt lỗi tùy chỉnh nữa.
Johnny Oshika

1
Câu trả lời có thay đổi trong MVC 5 không? Tôi không nhận được trang lỗi. Tất cả những gì tôi thấy là YSOD. Tôi có <customError mode = "On">. Còn thiếu gì nữa?
Dan
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.