Подтвердить что ты не робот

В ASP.NET MVC, что является лучшим показом необработанных исключений в моем представлении?

В моем web.config есть следующее:

 <customErrors mode="On" defaultRedirect="Error">
  <error statusCode="404" redirect="Error/NotFound" />
</customErrors>

У меня есть

 [HandleError]

в верхней части моего класса HomeController. Чтобы проверить, я создаю и действие, которое просто выдает исключение., и он перенаправляет на мой

 ErrorController/Index

но когда он дойдет до моего представления, которое связывается с HandleErrorInfo, моя модель равна нулю, поэтому я как-то потерял ссылку на ошибку.

Я уверен, что это имеет какое-то отношение к ошибке, потерянной в перенаправлении, поэтому я хотел посмотреть, не пропал ли я что-то, и если у кого-то есть предложения, где я могу иметь представление, отображающее сообщение Stacktrace и сообщение об ошибке.

4b9b3361

Ответ 1

Я вижу неправильное представление. Вы хотите сделать MVC вещь и redirect для действия контроллера.

Но defaultRedirect сам по себе является соглашением Web Form и тем самым ограничен. В тот момент, когда вы перенаправляетесь на другой контроллер, вы потеряете HttpContext и тем самым потеряете свой HandleErrorInfo Object

Для вашего атрибута [HandleError] требуется View, чтобы направить сообщение об ошибке. Следуя приведенному выше примеру, я предполагаю, что у вас есть Views/Error Папка для вашего ErrorController, и в ней вы видите Index Вид. Если вы хотите, чтобы ваш контекст фильтра отправил объект HandleErrorInfo в это представление,

Попробуйте этот синтаксис:

[HandleError(View="~/Views/Error/Index")]
Public class HomeController : Controller

Но как насчет Logging?!?!?

Я подозреваю, что ваше намерение больше, чем просто отображение стека ошибок для пользователей. На самом деле, я подозреваю, что у вас нет такого намерения. Я подозреваю, что ваша настоящая цель - зарегистрировать вашу ошибку (возможно, до db) и отобразить для пользователя свое сообщение.

То, что я объяснил до сих пор, было ", что лучше всего [показывать] необработанные исключения в моем представлении". Атрибут [HandleError] хорош для этого.

Но когда вы хотите перейти к следующему шагу (регистрируя ошибку), у вас есть несколько вариантов:

1) переопределить базовый контроллер On Exception method; создайте собственный Controller, наследующий класс MVC Controller, но переопределите метод исключения. Этот подход может использоваться в сочетании с атрибутом [HandleError]

2) Создать собственный обработчик исключений Создайте собственный обработчик исключений, который регистрирует ошибку. Затем ваш обработчик исключений может вызвать вид выбора или может работать в сочетании с [HandleError(order=2)], поскольку атрибуты фильтра могут принимать аргумент порядка, применяя приоритет.


Nitin Sawant спрашивает, как будет выглядеть сообщение об ошибке.

@model System.Web.Mvc.HandleErrorInfo
<h2>Exception details</h2>
<p> Controller: @Model.ControllerName </p>
<p> Action: @Model.ActionName </p>
<p> Exception: @Model.Exception </p>

Ответ 2

Я делаю что-то похожее на maxlego, которое обрабатывает все ошибки (а не только те, которые происходят в контроллерах с атрибутом HandleError).

Мой класс MvcApplication (в global.asax.cs) имеет следующее:

public class MvcApplication : HttpApplication
{
    // usual stuff here...

    protected void Application_Error(object sender, EventArgs e)
    {
        Server.HandleError(((MvcApplication)sender).Context);
    }
}

В приведенном выше коде используется метод расширения из моей библиотеки MVC полезных материалов. При этом мне не нужны атрибуты обработки ошибок, customErrors config или настраиваемые фильтры. Вместо этого метод расширения будет регистрировать данные об ошибках, а затем вызвать соответствующий вид:

  • AccessDenied
  • NotFound
  • InternalServerError

Код метода расширения для выполнения этой работы:

public static class HttpServerUtilityExtensions
{
    private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

    public static void HandleError(this HttpServerUtility server, HttpContext httpContext)
    {
        var currentController = " ";
        var currentAction = " ";
        var currentRouteData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext));

        if (currentRouteData != null)
        {
            if (currentRouteData.Values["controller"] != null && !String.IsNullOrEmpty(currentRouteData.Values["controller"].ToString()))
                currentController = currentRouteData.Values["controller"].ToString();

            if (currentRouteData.Values["action"] != null && !String.IsNullOrEmpty(currentRouteData.Values["action"].ToString()))
                currentAction = currentRouteData.Values["action"].ToString();
        }

        var exception = server.GetLastError();
        Logger.ErrorException(exception.Message, exception);

        var controller = DependencyResolver.Current.GetService<ErrorController>();
        var routeData = new RouteData();
        var action = "InternalServerError";

        if (exception is HttpException)
        {
            var httpEx = exception as HttpException;

            switch (httpEx.GetHttpCode())
            {
                case 404:
                    action = "NotFound";
                    break;

                case 401:
                    action = "AccessDenied";
                    break;
            }
        }

        httpContext.ClearError();
        httpContext.Response.Clear();
        httpContext.Response.StatusCode = exception is HttpException ? ((HttpException)exception).GetHttpCode() : 500;
        httpContext.Response.TrySkipIisCustomErrors = true;

        routeData.Values["controller"] = "Error";
        routeData.Values["action"] = action;

        controller.ViewData.Model = new HandleErrorInfo(exception, currentController, currentAction);
        ((IController)controller).Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData));
    }
}

Примечание. В приведенном выше примере NLog регистрирует данные об ошибках, но может быть легко изменен для поддержки чего-то еще. Кроме того, этот метод учитывает ваш контейнер IoC при разрешении ErrorController.

Ответ 3

Я использовал этот маленький фрагмент кода, чтобы показать страницу с обработанными пользователями ошибками. Не была ли найдена страница или какая-либо другая ошибка.

    void Application_Error(object sender, EventArgs e)
    {
        // this value can be fetched from config or depend on DEBUG smybol
        if (!handleErrors)
            return;

        var error = Server.GetLastError();
        var code = (error is HttpException) ? (error as HttpException).GetHttpCode() : 500;

        if (code == 404)
        {
            // do something if page was not found. log for instance
        }
        else
        {
            // collect request info and log exception
        }

        // pass exception to ErrorsController
        Request.RequestContext.RouteData.Values["ex"] = error;

        // execute controller action
        IController errorController = new ErrorsController();
        errorController.Execute(new RequestContext(new HttpContextWrapper(Context), Request.RequestContext.RouteData));
    }

И контроллер ошибок выглядит примерно так. Если вам нужно подробное исключение, оно доступно через RouteData​​p >

public class ErrorsController : Controller
{
    /// <summary>
    /// Page not found
    /// </summary>
    /// <returns></returns>
    public ActionResult Http404()
    {
        return View();
    }

    /// <summary>
    /// All other errors
    /// </summary>
    /// <param name="actionName"></param>
    protected override void HandleUnknownAction(string actionName)
    {
        // in case detailed exception is required.
        var ex = (Exception) RouteData.Values["ex"];
        return View();
    }
}

Вы можете добавить другое представление для каждого http-кода. Просто выполните действие Http {Code}