Ошибка HandleError ASP.NET MVC

Как мне использовать фильтр [HandleError] в asp.net MVC Preview 5?
Я установил customErrors в своем файле Web.config

<customErrors mode="On" defaultRedirect="Error.aspx">
  <error statusCode="403" redirect="NoAccess.htm"/>
  <error statusCode="404" redirect="FileNotFound.htm"/>
</customErrors>

и поместите [HandleError] над моим классом контроллера следующим образом:

[HandleError]
public class DSWebsiteController: Controller
{
    [snip]
    public ActionResult CrashTest()
    {
        throw new Exception("Oh Noes!");
    }
}

Затем я позволяю своим контроллерам наследовать от этого класса и вызываю для них CrashTest (). Visual Studio останавливается из-за ошибки, и после нажатия клавиши f5 для продолжения я перенаправляюсь на Error.aspx? Aspxerrorpath = / sxi.mvc / CrashTest (где sxi - это имя используемого контроллера. Конечно, путь не может быть найден, и я получаю «Ошибка сервера в приложении '/'.» 404.

Этот сайт был перенесен с предварительного просмотра 3 на 5. Все работает (не так уж много работы для переноса), кроме обработки ошибок. Когда я создаю полностью новый проект, кажется, что обработка ошибок работает.

Идеи?

--Примечание -
Поскольку сейчас у этого вопроса более 3К просмотров, я подумал, что было бы полезно добавить то, что я использую сейчас (ASP.NET MVC 1.0). В проекте mvc contrib есть замечательный атрибут под названием «RescueAttribute», вам, вероятно, тоже стоит его проверить;)


person Boris Callens    schedule 08.10.2008    source источник
comment
Ссылка на RescueAttribute источник: mvccontrib.code. com / SourceControl / changeset / view /   -  person Peter    schedule 13.01.2012


Ответы (5)


[HandleError]

Когда вы предоставляете своему классу (или методу действия) только атрибут HandleError, тогда при возникновении необработанного исключения MVC сначала будет искать соответствующее представление с именем «Ошибка» в папке представления контроллера. Если он не может найти его там, он продолжит поиск в папке общего просмотра (в которой по умолчанию должен быть файл Error.aspx).

[HandleError(ExceptionType = typeof(SqlException), View = "DatabaseError")]
[HandleError(ExceptionType = typeof(NullReferenceException), View = "LameErrorHandling")]

Вы также можете складывать дополнительные атрибуты с конкретной информацией о типе искомого исключения. На этом этапе вы можете направить ошибку в конкретное представление, отличное от представления «Ошибка» по умолчанию.

Для получения дополнительной информации посетите сообщение в блоге Скотта Гатри об этом.

person Elijah Manor    schedule 10.10.2008
comment
Спасибо за расширенную информацию. Я не знаю, что я сделал не так, но я создал новый проект, перенес в него все существующие представления, контроллеры и модели, и теперь он работает. Но про выборочные взгляды не знал. - person Boris Callens; 10.10.2008
comment
Если желательно ведение журнала этих исключений, будет ли это приемлемым местом для добавления внутреннего кода в представление? - person Peter J; 01.04.2009
comment
Iconic, лучше поздно, чем никогда не отвечать на ваш комментарий: вместо этого вы можете создать подкласс HandleErrorAttribute и переопределить его метод OnException: Затем вставьте любые желаемые действия для ведения журнала или настраиваемые действия. Затем вы можете либо полностью обработать исключение (установив для context.ExceptionHandled значение true), либо вернуться к собственному методу OnException базового класса. Вот отличная статья, которая может в этом помочь: blog.dantup.me.uk/2009/04/ - person Funka; 15.08.2009
comment
У меня много контроллеров, поэтому я могу справиться с этим внутри global.asax, например, this, чтобы показать сообщение пользователям? - person Shaiju T; 15.09.2016
comment
@ Как насчет того, чтобы использовать ту же страницу ошибок, что и PartialView, и отображать ее в модальном диалоговом окне после возникновения исключения? Не могли бы вы привести пример в своем ответе? То, чего я хочу достичь, было объяснено в Глобальной обработке ошибок с использованием PartialView в MVC. - person Jack; 20.09.2016

Также следует отметить, что ошибки, которые не устанавливают код ошибки http на 500

(например, UnauthorizedAccessException)

не будет обрабатываться фильтром HandleError.

person Corin Blaikie    schedule 22.07.2009
comment
Верно, но проверьте RescueAttribute в MVC contrib (ссылка в OP) - person Boris Callens; 04.12.2009

Решение для кода ошибки http на 500 это атрибут под названием [ERROR], поместите его в действие

public class Error: System.Web.Mvc.HandleErrorAttribute
{
    public override void OnException(System.Web.Mvc.ExceptionContext filterContext)
    {

            if (filterContext.HttpContext.IsCustomErrorEnabled)
            {
                filterContext.ExceptionHandled = true;

            }
            base.OnException(filterContext);
            //OVERRIDE THE 500 ERROR  
           filterContext.HttpContext.Response.StatusCode = 200;
    }

    private static void RaiseErrorSignal(Exception e)
    {
        var context = HttpContext.Current;
      // using.Elmah.ErrorSignal.FromContext(context).Raise(e, context);
    } 

}

//ПРИМЕР:

[Error]
[HandleError]
[PopulateSiteMap(SiteMapName="Mifel1", ViewDataKey="Mifel1")]
public class ApplicationController : Controller
{
}
person Raul    schedule 04.05.2010

Атрибуты в MVC очень полезны при обработке ошибок в методе get и post, он также отслеживает вызов ajax.

Создайте базовый контроллер в своем приложении и унаследуйте его в основном контроллере (EmployeeController).

открытый класс EmployeeController: BaseController

Добавьте ниже код в базовый контроллер.

/// <summary>
/// Base Controller
/// </summary>
public class BaseController : Controller
{       
    protected override void OnException(ExceptionContext filterContext)
    {
        Exception ex = filterContext.Exception;

        //Save error log in file
        if (ConfigurationManager.AppSettings["SaveErrorLog"].ToString().Trim().ToUpper() == "TRUE")
        {
            SaveErrorLog(ex, filterContext);
        }

        // if the request is AJAX return JSON else view.
        if (IsAjax(filterContext))
        {
            //Because its a exception raised after ajax invocation
            //Lets return Json
            filterContext.Result = new JsonResult()
            {
                Data = Convert.ToString(filterContext.Exception),
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            };
        }
        else
        {
            filterContext.ExceptionHandled = true;
            filterContext.HttpContext.Response.Clear();

            filterContext.Result = new ViewResult()
            {
                //Error page to load
                ViewName = "Error",
                ViewData = new ViewDataDictionary()
            };

            base.OnException(filterContext);
        }
    }

    /// <summary>
    /// Determines whether the specified filter context is ajax.
    /// </summary>
    /// <param name="filterContext">The filter context.</param>
    private bool IsAjax(ExceptionContext filterContext)
    {
        return filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest";
    }

    /// <summary>
    /// Saves the error log.
    /// </summary>
    /// <param name="ex">The ex.</param>
    /// <param name="filterContext">The filter context.</param>
    void SaveErrorLog(Exception ex, ExceptionContext filterContext)
    {
        string logMessage = ex.ToString();

        string logDirectory = Server.MapPath(Url.Content("~/ErrorLog/"));

        DateTime currentDateTime = DateTime.Now;
        string currentDateTimeString = currentDateTime.ToString();
        CheckCreateLogDirectory(logDirectory);
        string logLine = BuildLogLine(currentDateTime, logMessage, filterContext);
        logDirectory = (logDirectory + "\\Log_" + LogFileName(DateTime.Now) + ".txt");

        StreamWriter streamWriter = null;
        try
        {
            streamWriter = new StreamWriter(logDirectory, true);
            streamWriter.WriteLine(logLine);
        }
        catch
        {
        }
        finally
        {
            if (streamWriter != null)
            {
                streamWriter.Close();
            }
        }
    }

    /// <summary>
    /// Checks the create log directory.
    /// </summary>
    /// <param name="logPath">The log path.</param>
    bool CheckCreateLogDirectory(string logPath)
    {
        bool loggingDirectoryExists = false;
        DirectoryInfo directoryInfo = new DirectoryInfo(logPath);
        if (directoryInfo.Exists)
        {
            loggingDirectoryExists = true;
        }
        else
        {
            try
            {
                Directory.CreateDirectory(logPath);
                loggingDirectoryExists = true;
            }
            catch
            {
            }
        }

        return loggingDirectoryExists;
    }

    /// <summary>
    /// Builds the log line.
    /// </summary>
    /// <param name="currentDateTime">The current date time.</param>
    /// <param name="logMessage">The log message.</param>
    /// <param name="filterContext">The filter context.</param>       
    string BuildLogLine(DateTime currentDateTime, string logMessage, ExceptionContext filterContext)
    {
        string controllerName = filterContext.RouteData.Values["Controller"].ToString();
        string actionName = filterContext.RouteData.Values["Action"].ToString();

        RouteValueDictionary paramList = ((System.Web.Routing.Route)(filterContext.RouteData.Route)).Defaults;
        if (paramList != null)
        {
            paramList.Remove("Controller");
            paramList.Remove("Action");
        }

        StringBuilder loglineStringBuilder = new StringBuilder();

        loglineStringBuilder.Append("Log Time : ");
        loglineStringBuilder.Append(LogFileEntryDateTime(currentDateTime));
        loglineStringBuilder.Append(System.Environment.NewLine);

        loglineStringBuilder.Append("Username : ");
        loglineStringBuilder.Append(Session["LogedInUserName"]);
        loglineStringBuilder.Append(System.Environment.NewLine);

        loglineStringBuilder.Append("ControllerName : ");
        loglineStringBuilder.Append(controllerName);
        loglineStringBuilder.Append(System.Environment.NewLine);

        loglineStringBuilder.Append("ActionName : ");
        loglineStringBuilder.Append(actionName);
        loglineStringBuilder.Append(System.Environment.NewLine);

        loglineStringBuilder.Append("----------------------------------------------------------------------------------------------------------");
        loglineStringBuilder.Append(System.Environment.NewLine);

        loglineStringBuilder.Append(logMessage);
        loglineStringBuilder.Append(System.Environment.NewLine);
        loglineStringBuilder.Append("==========================================================================================================");

        return loglineStringBuilder.ToString();
    }

    /// <summary>
    /// Logs the file entry date time.
    /// </summary>
    /// <param name="currentDateTime">The current date time.</param>
    string LogFileEntryDateTime(DateTime currentDateTime)
    {
        return currentDateTime.ToString("dd-MMM-yyyy HH:mm:ss");
    }

    /// <summary>
    /// Logs the name of the file.
    /// </summary>
    /// <param name="currentDateTime">The current date time.</param>
    string LogFileName(DateTime currentDateTime)
    {
        return currentDateTime.ToString("dd_MMM_yyyy");
    }

}

================================================

Находит каталог: Root / App_Start / FilterConfig.cs

Добавьте ниже код:

/// <summary>
/// Filter Config
/// </summary>
public class FilterConfig
{
    /// <summary>
    /// Registers the global filters.
    /// </summary>
    /// <param name="filters">The filters.</param>
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
    }
}

Отслеживание ошибки AJAX:

Вызовите функцию CheckAJAXError при загрузке страницы макета.

function CheckAJAXError() {
    $(document).ajaxError(function (event, jqXHR, ajaxSettings, thrownError) {

        var ex;
        if (String(thrownError).toUpperCase() == "LOGIN") {
            var url = '@Url.Action("Login", "Login")';
            window.location = url;
        }
        else if (String(jqXHR.responseText).toUpperCase().indexOf("THE DELETE STATEMENT CONFLICTED WITH THE REFERENCE CONSTRAINT") >= 0) {

            toastr.error('ReferanceExistMessage');
        }
        else if (String(thrownError).toUpperCase() == "INTERNAL SERVER ERROR") {
            ex = ajaxSettings.url;
            //var url = '@Url.Action("ErrorLog", "Home")?exurl=' + ex;
            var url = '@Url.Action("ErrorLog", "Home")';
            window.location = url;
        }
    });
};
person Sandip - Frontend Developer    schedule 19.07.2016
comment
Вы теряете сведения об исключении в запросах AJAX, вы не всегда этого хотите. Ваш код ведения журнала не является потокобезопасным. Вы предполагаете, что есть представление Error, и возвращаете его, не изменяя код ответа. Затем вы проверяете определенные строки ошибок в JavaScript (как насчет локализации?). По сути, вы повторяете то, что уже сказано в существующем ответе: Переопределить OnException для обработки исключений, но демонстрируете довольно плохую его реализацию. - person CodeCaster; 20.09.2016
comment
Что такое параметр @ School.Resource.Messages.ReferanceExist? - person Jack; 20.09.2016
comment
@CodeCaster Знаете ли вы лучший способ использования такого метода обработки ошибок с помощью AJAX в ASP.NET MVC? Любая помощь, пожалуйста? - person Jack; 20.09.2016
comment
Верните 400 или 500, как предполагается в HTTP. Не копайтесь в конкретных строках в теле ответа. - person CodeCaster; 20.09.2016
comment
@CodeCaster Не могли бы вы взглянуть на Обработку глобальных ошибок используя PartialView в MVC относительно этой проблемы? - person Jack; 20.09.2016
comment
@SandipPatel Большое спасибо. Я пробовал этот метод, но когда в контроллере возникает исключение, я возвращаю JSON в связанный вызов AJAX, а затем вызываю ваш метод CheckAJAXError (). Но когда я отлаживаю с помощью Firebug, он возвращается после первой строки этого метода Javascript. Есть ли какая-либо реализация в моем методе контроллера (я уже унаследовал от BaseController). Любая идея? - person Jack; 20.09.2016

Вам не хватает Error.aspx :) В предварительной версии 5 он находится в вашей папке Views / Shared. Просто скопируйте его из нового проекта Preview 5.

person Ricky    schedule 08.10.2008
comment
Спасибо за ответ, но я уже скопировал страницу Error.aspx. Могло действительно быть то, о чем я обычно забыл, но не в этот раз. :П - person Boris Callens; 09.10.2008