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

Обработка исключений в контроллере (ASP.NET MVC)

Когда исключение генерируется вашим собственным кодом, вызываемым из действия контроллера, как это должно быть обработано? Я вижу множество примеров лучших практик, в которых вообще нет заявлений о попытках. Например, доступ к данным из репозитория:

public ViewResult Index()
{
    IList<CustomModel> customModels = _customModelRepository.GetAll();
    return View(customModels);
}

Очевидно, что этот код может генерировать исключение, если вызов относится к базе данных, к которой он не может получить доступ, и мы используем ORM, например, Entity Framework.

Однако все, что я вижу, будет состоять в том, что исключение будет пузыриться и отображать неприятное сообщение об ошибке для пользователя.

Мне известно об атрибуте HandleError, но я понимаю, что в основном используется для перенаправления на страницу с ошибкой, если происходит исключение, которое необработанное.

Конечно, этот код можно было бы обернуть в try-catch, но он не будет отлично отделяться, особенно если у вас больше логики:

public ViewResult Index()
{
    if (ValidationCheck())
    {
        IList<CustomModel> customModels = new List<CustomModel>();
        try
        {
            customModels = _customModelRepository.GetAll();
        }
        catch (SqlException ex)
        {
            // Handle exception
        }

        if (CustomModelsAreValid(customModels))
            // Do something
        else
            // Do something else
    }

    return View();
}

Раньше я извлекал весь код, который мог бы вызывать исключения, такие как вызовы базы данных, в класс DataProvider, который обрабатывает ошибки и возвращает сообщения для отображения сообщений пользователю.

Мне было интересно, какой лучший способ справиться с этим? Я не всегда хочу вернуться на страницу с ошибкой, потому что некоторые исключения не должны этого делать. Вместо этого сообщение об ошибке для пользователя должно отображаться с нормальным представлением. Был ли мой предыдущий метод правильным или есть лучшее решение?

4b9b3361

Ответ 1

Я делаю три вещи, чтобы отображать более удобные для пользователя сообщения:

  • Воспользуйтесь глобальным обработчиком исключений. В случае MVC: Application_Error в Global.asax. Узнайте, как его использовать здесь: http://msdn.microsoft.com/en-us/library/24395wz3 (v = vs .100).aspx
  • я подкласс Exception в UserFriendlyException. Я делаю все возможное во всех моих базовых классах сервиса, чтобы выбросить это UserFriendlyException вместо простого старого исключения. Я всегда стараюсь помещать пользовательские сообщения в эти пользовательские исключения. Основная цель которого - сделать проверку типа исключения в методе Application_Error. Для UserFriendlyExceptions я просто использую удобное для пользователя сообщение, которое я установил в своих сервисах, например "Hey! 91 градусов - это не допустимое значение широты!". Если это регулярное исключение, то в каком-то случае я не обрабатывал, поэтому я показываю более общее сообщение об ошибке, например "Ой, что-то пошло не так! Мы сделаем все возможное, чтобы это исправлено!".
  • Я также создаю ErrorController, который отвечает за рендеринг пользовательских представлений или JSON. Это контроллер, методы которого будут вызываться из метода Application_Error.

EDIT: Я думал, что буду упоминать ASP.NET Web API, поскольку он тесно связан. Поскольку пользователь конечных точек Web API не обязательно будет браузером, мне нравится иметь дело с ошибками немного по-другому. Я все еще использую "FriendlyException" (# 2 выше), но вместо перенаправления на ErrorController я просто позволяю всем своим конечным точкам возвращать некоторый тип базового типа, который содержит свойство Error. Таким образом, если исключение пузырится до контроллера веб-API, я обязательно придерживаюсь этой ошибки в свойстве Error для ответа API. Это сообщение об ошибке будет либо дружественным сообщением, которое пузырилось из классов, на которые опирается контроллер API, либо будет общим сообщением, если тип исключения не является понятием FriendlyException. Таким образом, потребитель-клиент может просто проверить, не является ли свойство Error для ответа API пустым. Отобразите сообщение, если ошибка присутствует, как обычно, выполняйте, если нет. Приятно то, что из-за концепции дружественного сообщения сообщение может быть намного более значимым для пользователя, чем общая "Ошибка!". сообщение. Я использую эту стратегию при написании мобильных приложений с помощью Xamarin, где я могу делиться своими типами С# между моими веб-сервисами и моим приложением iOS/Android.

Ответ 2

С помощью Asp.Net MVC вы также можете переопределить метод OnException для вашего контроллера.

protected override void OnException(ExceptionContext filterContext)
{
    if (filterContext.ExceptionHandled)
    {
        return;
    }
    filterContext.Result = new ViewResult
    {
        ViewName = ...
    };
    filterContext.ExceptionHandled = true;
}

Это позволит вам перенаправить на страницу пользовательских ошибок сообщение, которое ссылается на исключение, если вы хотите.

Ответ 3

Я использовал переопределение OnException, потому что у меня есть несколько проектов, связанных с тем, у кого есть контроллер, который обрабатывает ошибки:

Безопасность/HandleErrorsController.cs

protected override void OnException(ExceptionContext filterContext) 
{
    MyLogger.Error(filterContext.Exception);   //method for log in EventViewer

    if (filterContext.ExceptionHandled)
        return;

    filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;

    filterContext.Result = new JsonResult
    {
        Data = new
        {
            Success = false, 
            Error = "Please report to admin.",
            ErrorText = filterContext.Exception.Message,
            Stack = filterContext.Exception.StackTrace
        },
        JsonRequestBehavior = JsonRequestBehavior.AllowGet
    };
    filterContext.ExceptionHandled = true;
}

Ответ 4

Все вопросы, подобные этому, не очень конструктивны, потому что ответ всегда "зависит", потому что существует так много способов справиться с обработкой ошибок.

Многие люди любят использовать метод HandleError, потому что любое исключение в основном не восстанавливается. Я имею в виду, что вы собираетесь делать, если вы не можете вернуть объекты? Вы все равно покажете им ошибку, верно?

Вопрос становится, как вы хотите показать им ошибку. Если показывать их, то страница с ошибкой приемлема, чем HandleError отлично работает и обеспечивает удобное место для регистрации ошибки. Если вы используете Ajax или хотите что-то более интересное, вам нужно разработать способ сделать это.

Вы говорите о классе DataProvider. Это в основном то, что ваш репозиторий. Почему бы не создать это в вашем репозитории?