Как мне использовать фильтр [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. Все работает (портировать было не так уж много), кроме обработки ошибок. Когда я создаю полностью новый проект, обработка ошибок, похоже, работает.
Идеи?
--Примечание--
Поскольку этот вопрос сейчас имеет более 3K просмотров, я подумал, что было бы полезно добавить то, что я использую сейчас (ASP.NET MVC 1.0).
В проект mvc contrib есть замечательный атрибут под названием "RescueAttribute"
Вам, наверное, тоже стоит это проверить;)





Вам не хватает Error.aspx :) В предварительной версии 5 он находится в вашей папке Views / Shared. Просто скопируйте его из нового проекта Preview 5.
Спасибо за ответ, но я уже скопировал страницу Error.aspx. Я действительно мог бы забыть о чем-то, но не в этот раз. :П
[HandleError]
Когда вы предоставляете своему классу (или методу действия) только атрибут HandleError, тогда при возникновении необработанного исключения MVC сначала будет искать соответствующее представление с именем «Ошибка» в папке представления контроллера. Если он не может найти его там, он продолжит поиск в папке общего просмотра (в которой по умолчанию должен быть файл Error.aspx).
[HandleError(ExceptionType = typeof(SqlException), View = "DatabaseError")]
[HandleError(ExceptionType = typeof(NullReferenceException), View = "LameErrorHandling")]
Вы также можете складывать дополнительные атрибуты с конкретной информацией о типе искомого исключения. На этом этапе вы можете направить ошибку в конкретное представление, отличное от представления «Ошибка» по умолчанию.
Для получения дополнительной информации ознакомьтесь с Сообщение в блоге Скотта Гатри об этом.
Спасибо за расширенную информацию. Не знаю, что я сделал не так, но я создал новый проект, перенес в него все существующие представления, контроллеры и модели, и теперь он работает. Но про выборочные взгляды не знал.
Если требуется регистрация этих исключений, будет ли это приемлемым местом для добавления выделенного кода в представление?
Iconic, вот мой ответ «лучше поздно, чем никогда» на ваш комментарий: вместо этого вы можете создать подкласс HandleErrorAttribute и переопределить его метод «OnException»: затем вставьте любое желаемое ведение журнала или настраиваемые действия. Затем вы можете либо полностью обработать исключение (установив для context.ExceptionHandled значение true), либо вернуться для этого к собственному методу OnException базового класса. Вот отличная статья, которая может в этом помочь: blog.dantup.me.uk/2009/04/…
У меня много контроллеров, могу ли я справиться с этим внутри global.asax, например это, чтобы показать сообщение пользователям?
@ Как насчет того, чтобы использовать ту же страницу ошибок, что и PartialView, и отображать ее в модальном диалоговом окне после возникновения исключения? Не могли бы вы привести пример в своем ответе? То, чего я хочу достичь, было объяснено на Глобальная обработка ошибок с использованием PartialView в MVC.
Также следует отметить, что ошибки, которые не устанавливают код ошибки http на 500
(например, UnauthorizedAccessException)
не будет обрабатываться фильтром HandleError.
Верно, но проверьте RescueAttribute в MVC contrib (ссылка в OP)
Решение для кода ошибки 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
{
}
[HandleError]
public class ErrorController : Controller
{
[AcceptVerbs(HttpVerbs.Get)]
public ViewResult NotAuthorized()
{
//401
Response.StatusCode = (int)HttpStatusCode.Unauthorized;
return View();
}
[AcceptVerbs(HttpVerbs.Get)]
public ViewResult Forbidden()
{
//403
Response.StatusCode = (int)HttpStatusCode.Forbidden;
return View();
}
[AcceptVerbs(HttpVerbs.Get)]
public ViewResult NotFound()
{
//404
Response.StatusCode = (int)HttpStatusCode.NotFound;
return View();
}
public ViewResult ServerError()
{
//500
Response.StatusCode = (int)HttpStatusCode.NotFound;
return View();
}
}
Атрибуты в MVC очень полезны при обработке ошибок в методе получить и опубликовать, он также отслеживает вызов 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;
}
});
};
Вы теряете сведения об исключении в запросах AJAX, вы не всегда этого хотите. Ваш код ведения журнала не является потокобезопасным. Вы предполагаете, что есть представление Error, и возвращаете его, не изменяя код ответа. Затем вы проверяете определенные строки ошибок в JavaScript (как насчет локализации?). В основном вы повторяете то, что уже сказано в существующем ответе: «Переопределить OnException для обработки исключений», но демонстрируете довольно плохую его реализацию.
Что такое параметр @ School.Resource.Messages.ReferanceExist?
@CodeCaster Знаете ли вы лучший способ использования такого метода обработки ошибок с помощью AJAX в ASP.NET MVC? Любая помощь, пожалуйста?
Верните 400 или 500, как предполагается в HTTP. Не ищите конкретные строки в теле ответа.
@CodeCaster Не могли бы вы взглянуть на Глобальная обработка ошибок с использованием PartialView в MVC относительно этой проблемы?
@SandipPatel Большое спасибо. Я пробовал этот метод, но когда в контроллере возникает исключение, я возвращаю JSON в связанный вызов AJAX, а затем вызываю ваш метод CheckAJAXError (). Но когда я отлаживаю с помощью Firebug, он возвращается после первой строки этого метода Javascript. Есть ли какая-либо реализация в моем методе контроллера (я уже унаследовал от BaseController). Любая идея?
Ссылка на источник
RescueAttribute: mvccontrib.codeplex.com/SourceControl/changeset/view/…