c# - ASP.NET MVC - 全局错误处理方法?

标签 c# asp.net asp.net-mvc

我想知道全局错误(不一定是错误,也可以是成功消息)处理程序的最佳实现是什么?让我用一个例子为你分解一下:

  1. 用户试图删除一条记录
  2. 删除失败并记录错误
  3. 用户重定向到另一个页面
  4. 为用户显示错误消息(使用 HtmlHelper 或其他东西,不希望它是特定的错误页面)

我很好奇你们是怎么想的。我一直在考虑 TempData、ViewData 和 Session,但它们各有利弊。

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);
    }
}

并且在 View “RecordsList”中,在 HtmlHelper 或其他东西中显示所有消息(包括错误消息和成功消息)会有点酷。

<%= Html.RenderAllMessages %>

这可以通过多种方式实现,我只是好奇你们会怎么做。

更新 2:

我已经创建了一个自定义错误(消息)处理程序。如果向下滚动,您可以看到代码。

最佳答案

为了好玩,我创建了自己的自定义错误(消息)处理程序,它的工作方式与 TempData 非常相似,但有一点不同,即此处理程序可在整个应用程序中访问。

我不打算解释代码的每一步,但总而言之,我使用 IHttpModule 为每个请求触发一个方法,并使用 Session 保存数据。以下是代码,欢迎随时编辑或提出改进建议。

Web.config(定义模块)

<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) %>

关于c# - ASP.NET MVC - 全局错误处理方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7099973/

相关文章:

c# - 索引器和存储位置

c# - 如何在不禁用验证的情况下将 HTML 或其他类似标记安全地传递到文本框中?

c# - 如何缓存处理程序图像?

c# - ASP.NET 5 MVC : unable to connect to web server 'IIS Express'

asp.net - 使用嵌套集合更新模型,ASP.NET MVC

c# - 在 MVC 中使用 DropDownList 中的选定项

c# - 查找重复记录并将记录合并到单个数据表 c#

c# - 在 C# 中处理编码的 cookie 值

c# - 在 C# 中访问 Excel 单元格值

c# - 如何避免在选择 DropDownList 时刷新页面