ASP.全局错误处理方法
本文关键字:方法 处理 错误 全局 ASP | 更新日期: 2023-09-27 18:06:01
我想知道全局错误(不一定是错误,也可以是成功消息)处理程序的最佳实现是什么?让我用一个例子给你解释一下:
- 用户试图删除记录
- 删除失败并记录错误
- 用户重定向到另一个页面
- 为用户显示错误信息(使用HtmlHelper或其他东西,不希望它是一个特定的错误页面)
TIA !
更新:
我将展示一个例子,我到底是什么意思,也许我不够清楚。这是一个在用户删除记录时添加消息的方法示例。如果用户成功,用户将重定向到另一个页面
public ActionResult DeleteRecord(Record recordToDelete)
{
// If user succeeds deleting the record
if (_service.DeleteRecord(recordToDelete)
{
// Add success message
MessageHandler.AddMessage(Status.SUCCESS, "A message to user");
// And redirect to list view
return RedirectToAction("RecordsList");
}
else
{
// Else return records details view
return View("RecordDetails", recordToDelete);
}
}
在视图"RecordsList"中,在HtmlHelper或其他东西中显示所有消息(包括错误和成功消息)会有点酷。
<%= Html.RenderAllMessages %>
这可以通过很多方式实现,我只是好奇你们会怎么做。
更新2:我创建了一个自定义错误(消息)处理程序。如果向下滚动,可以看到代码
只是为了好玩,我创建了自己的自定义错误(消息)处理程序,它的工作原理与TempData非常相似,但有一点不同,这个处理程序可以在整个应用程序中访问。
我不打算解释代码的每一步,但是总结一下,我使用IHttpModule为每个请求和Session触发一个方法来保存数据。以下是代码,请随意编辑或提出改进建议。网络。config (Define module)
<httpModules>
<add name="ErrorManagerModule" type="ErrorManagerNamespace.ErrorManager"/>
</httpModules>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="ErrorManagerModule" type="ErrorManagerNamespace.ErrorManager"/>
</modules>
</system.webServer>
ErrorManager.cs(错误管理器处理代码)
public class ErrorManager : IRequiresSessionState, IHttpModule
{
private const string SessionKey = "ERROR_MANAGER_SESSION_KEY";
public enum Type
{
None,
Warning,
Success,
Error
}
/*
*
* Public methods
*
*/
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.AcquireRequestState += new EventHandler(Initiliaze);
}
public static IList<ErrorModel> GetErrors(ErrorManager.Type type = Type.None)
{
// Get all errors from session
var errors = GetErrorData();
// Destroy Keep alive
// Decrease all errors request count
foreach (var error in errors.Where(o => type == ErrorManager.Type.None || o.ErrorType == type).ToList())
{
error.KeepAlive = false;
error.IsRead = true;
}
// Save errors to session
SaveErrorData(errors);
//return errors;
return errors.Where(o => type == ErrorManager.Type.None || o.ErrorType == type).ToList();
}
public static void Add(ErrorModel error)
{
// Get all errors from session
var errors = GetErrorData();
var result = errors.Where(o => o.Key.Equals(error.Key, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
// Add error to collection
error.IsRead = false;
// Error with key is already associated
// Remove old error from collection
if (result != null)
errors.Remove(result);
// Add new to collection
// Save errors to session
errors.Add(error);
SaveErrorData(errors);
}
public static void Add(string key, object value, ErrorManager.Type type = Type.None, bool keepAlive = false)
{
// Create new error
Add(new ErrorModel()
{
IsRead = false,
Key = key,
Value = value,
KeepAlive = keepAlive,
ErrorType = type
});
}
public static void Remove(string key)
{
// Get all errors from session
var errors = GetErrorData();
var result = errors.Where(o => o.Key.Equals(key, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
// Error with key is in collection
// Remove old error
if (result != null)
errors.Remove(result);
// Save errors to session
SaveErrorData(errors);
}
public static void Clear()
{
// Clear all errors
HttpContext.Current.Session.Remove(SessionKey);
}
/*
*
* Private methods
*
*/
private void Initiliaze(object o, EventArgs e)
{
// Get context
var context = ((HttpApplication)o).Context;
// If session is ready
if (context.Handler is IRequiresSessionState ||
context.Handler is IReadOnlySessionState)
{
// Load all errors from session
LoadErrorData();
}
}
private static void LoadErrorData()
{
// Get all errors from session
var errors = GetErrorData().Where(o => !o.IsRead).ToList();
// If KeepAlive is set to false
// Mark error as read
foreach (var error in errors)
{
if (error.KeepAlive == false)
error.IsRead = true;
}
// Save errors to session
SaveErrorData(errors);
}
private static void SaveErrorData(IList<ErrorModel> errors)
{
// Make sure to remove any old errors
HttpContext.Current.Session.Remove(SessionKey);
HttpContext.Current.Session.Add(SessionKey, errors);
}
private static IList<ErrorModel> GetErrorData()
{
// Get all errors from session
return HttpContext.Current.Session[SessionKey]
as IList<ErrorModel> ??
new List<ErrorModel>();
}
/*
*
* Model
*
*/
public class ErrorModel
{
public string Key { get; set; }
public object Value { get; set; }
public bool KeepAlive { get; set; }
internal bool IsRead { get; set; }
public Type ErrorType { get; set; }
}
HtmlHelperExtension.cs(一个显示错误的扩展方法)
public static class HtmlHelperExtension
{
public static string RenderMessages(this HtmlHelper obj, ErrorManager.Type type = ErrorManager.Type.None, object htmlAttributes = null)
{
var builder = new TagBuilder("ul");
var errors = ErrorManager.GetErrors(type);
// If there are no errors
// Return empty string
if (errors.Count == 0)
return string.Empty;
// Merge html attributes
builder.MergeAttributes(new RouteValueDictionary(htmlAttributes), true);
// Loop all errors
foreach (var error in errors)
{
builder.InnerHtml += String.Format("<li class='"{0}'"><span>{1}</span></li>",
error.ErrorType.ToString().ToLower(),
error.Value as string);
}
return builder.ToString();
}
}
创建错误的用法
// This will only be available for one request
ErrorManager.Add("Key", "An error message", ErrorManager.Type.Error);
// This will be available for multiple requests
// When error is read, it will be removed
ErrorManager.Add("Key", "An error message", ErrorManager.Type.Error, true);
// Remove an error
ErrorManager.Remove("AnotherKey");
// Clear all error
ErrorManager.Clear();
显示错误的用法
// This will render all errors
<%= Html.RenderMessages() %>
// This will just render all errors with type "Error"
<%= Html.RenderMessages(ErrorManager.Type.Error) %>
我对这些步骤感到困惑:
- 删除失败并记录错误
- 用户重定向到另一个页面
当错误发生时,为什么要重定向用户?这没有任何意义,除非我误解了什么。
一般来说,我遵循以下准则:
-
表单提交错误(例如HTTP POST):检查
ModelState.IsValid
并返回相同的视图并呈现@Html.ValidationSummary()
错误 -
错误与AJAX调用:返回
JsonResult
(如@Tomas说),并使用基本的客户端脚本检查JSON并显示结果 -
错误与域/业务:抛出自定义异常,让控制器捕获它们,并添加到
ModelState
如上
我更喜欢把我的服务器层写成一个在ASP中发出JSON的API。NET MVC,这是非常简单的-你只是创建一堆嵌套的匿名对象,和return Json(data);
。JSON对象然后由客户端层使用,该层由html、css和javascript组成(我经常使用jQuery,但您可能更喜欢其他工具)。
因为javascript是动态的,所以很容易在数据对象上有一个属性status
,客户端脚本可以解释它,并根据需要显示状态或错误消息。
例如,考虑以下动作方法:
public ActionResult ListStuff()
{
var stuff = Repo.GetStuff();
return Json(new { status = "OK", thestuff = stuff });
}
这将以以下格式返回JSON:
{ "status": "OK", "thestuf": [{ ... }, { ... }] }
,其中...
是stuff
属性的占位符。现在,如果我想处理错误,我可以输入
try
{
var stuff = Repo.GetStuff();
return Json(new { status = "OK", thestuff = stuff});
}
catch (Exception ex)
{
Log.Error(ex);
return Json(new { status = "Fail", reason = ex.Message });
}
由于javascript是动态的,所以两个匿名对象是否具有相同的属性并不重要。根据status
的值,我将只查找实际存在的属性。
如果您创建自己的操作结果类,可以更好地实现这一点,这些类扩展JsonResult
并自动添加status属性。例如,您可以为失败的请求创建一个,该请求在构造函数中接受异常;为成功的请求创建一个,而不是接受匿名对象。
如果你要做的只是将用户重定向到另一个页面,那么你可以使用任何ActionMethod来这样做,并直接重定向到它。
如果您想要一个全局错误,例如500或403或其他一些错误,那么MVC 3默认模板为您创建一个_Error.cshtml
页面并在global.asax
中注册错误处理程序。
如果您想捕获特定的错误,那么您可以在同一位置注册其他处理程序,并告诉系统该错误使用哪个错误页。