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

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

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, который обрабатывает ошибки и возвращает сообщения для отображения сообщений пользователю.

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

4 ответов


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

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

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


С Asp.Net MVC также можно переопределить метод OnException для контроллера.

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

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


я использовал переопределение 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;
}

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

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

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

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