MVC5 - 控制器的“通用”包装器

本文关键字:包装 通用 控制器 MVC5 | 更新日期: 2023-09-27 18:35:17

我的MVC5控制器有一个"通用"返回值,它返回类似

{ Success: true, 
Item: {Id:1, Name:"Oink" },
Error:null,
Message:"Everything works fine"
}

即使发生异常,我也想保留此结构。所以目前我在控制器中使用这样的东西:

try {
    var stuff=new Stuff();
    return ReturnSomeJson(stuff.GetStuff(),"Everything works fine", true, null);
} 
catch (Exception ex)
{
    return ReturnSomeJson(null, "That went wrong!", false, ex);
}

所以这是返回方法:

protected ReturnSomeJson (object item, string message, bool success, exception ex) {
    // more stuff
    return Json (this);
}

由于这是一个非常通用的异常处理,我想避免一遍又一遍地编写这个 try-catch。

我已经了解了MVC中的不同异常方法,但是所有这些方法都直接显示错误消息。

但是我想在使用通用错误处理时保留"ActionResult"返回值。

MVC5 - 控制器的“通用”包装器

我已经研究了异常处理问题,我的结论是,放置通用错误处理程序的最佳位置是global.asax.cs,Application_Error方法。此外,禁用您可以找到的所有其他错误处理(包括 MVC 的处理),因为这可以在您不知情的情况下捕获并吞下异常。

我选择Application_Error因为它是绝对的最终处理程序。如果这没有捕获流氓异常(没有被吞噬),那么什么都不会。例如,如果使用 MVC 错误处理,则仍然可能会遗漏一些错误 - 例如Application_BeginRequest中的异常或缺少控制器,或 DLL 加载异常或其他任何错误。

如果不想在每个控制器操作中编写 Try Catch 语句,可以创建自己的异常处理程序。通过覆盖HandleErrorAttributeOnException方法。

您现在不必将try{}catch()添加到每个操作中,因为当发生异常时,它将调用ExceptionHandlerAttributeOnException

我有一个看起来像这样:

public class ExceptionHandlerAttribute : HandleErrorAttribute
{
    private static readonly string[] DefinedException = { "SessionTimeOutException", "UnauthorizedAccessException" };
    public override void OnException(ExceptionContext filterContext)
    {
        if (filterContext.ExceptionHandled)
            return;
        var validationContainer = new ValidationContainer();
        filterContext.ExceptionHandled = true;
        var exceptionName = filterContext.Exception.GetType().Name;
        string exceptionMessage;
        if (DefinedException.Contains(exceptionName))
        {
            exceptionMessage = filterContext.Exception.Message;
        }
        else
        {
            exceptionMessage = "We intentionally allowed to not catch exception to track the root causes. Please note down the steps and include following details in the bug.</br>"
                               + "</br></br>Exception Message: " + filterContext.Exception;
        }
        validationContainer.AddMessage(MessageType.Error, exceptionMessage);
        filterContext.Result = new JsonResult
        {
            Data = validationContainer,
            JsonRequestBehavior = JsonRequestBehavior.AllowGet
        };
    }
}

我在这里添加了 ValidationContainer 类(因为它在上面使用)

public class ValidationContainer
{
    public List<string> ErrorMessages { get; set; }
    public List<string> SuccessMessages { get; set; }
    public List<string> WarningMessages { get; set; }
    public List<string> InformationMessages { get; set; }
    public void AddMessage(MessageType messageType, string message)
    {
        switch (messageType)
        {
            case MessageType.Information:
                InformationMessages.Add(message);
                break;
            case MessageType.Success:
                SuccessMessages.Add(message);
                break;
            case MessageType.Error:
                ErrorMessages.Add(message);
                break;
            case MessageType.Warning:
                WarningMessages.Add(message);
                break;
        }
    }
}
public enum MessageType
{
    Error = 1,
    Success = 2,
    Warning = 3,
    Information = 4,
    Debug = 5,
}

然后,您可以在控制器中使用它:

[ExceptionHandler]
public class HomeController : BaseController
{
}

或在操作上

    [ExceptionHandler]
    public ActionResult index()
    {
        return Json();
    }

我用这种方式使用它

public abstract class ApiResult
{
    /// <summary>
    /// is success
    /// </summary>
    public bool Success { get; set; }
    /// <summary>
    /// I think you want use a error code here
    /// </summary>
    public string Error{get;set;}
    /// <summary>
    /// message
    /// </summary>
    public string Message { get; set; }
    /// <summary>
    /// error 
    /// </summary>
    /// <param name="message"></param>
    /// <returns></returns>
    public ApiResult Error(string message)
    {
        return new ErrorApiResult(message);
    }
    /// <summary>
    /// Success
    /// </summary>
    /// <param name="data"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static ApiResult<T> Success<T>(T data)
    {
        return new ApiResult<T>()
        {
            Success = true,
            Message = null,
            Data = data
        };
    }
}
public class ErrorApiResult:ApiResult {
    public ErrorApiResult(string errorCode,string message)
    {
        Message = message;
        Success = false;
        Error = errorCode;
    }
}
public class ApiResult<T>: ApiResult
{
    /// <summary>
    /// the success return data
    /// </summary>
    public T Data { get; set; }
    public static ApiResult<T> Error(string message)
    {
        return new ApiResult<T>() {Message = message, Success = true};
    }
    public static ApiResult<T> Error(bool isSuccess,string message)
    {
        return new ApiResult<T>() {Message = message, Success =isSuccess};
    }
}

您可以在您的方法中使用它:

... ReturnSomeJson (object item, string message, bool success, exception ex) {
    if(success){
       return Json(new ApiResult.....)
    }
    // more stuff
    return Json (this);
}

但我认为差异方法更好:

ActionResult Error(string error,string message,Exception ex){
    var json = new ErrorApiResult(error,message);
    return Json(json);
}
ActionResult Success<T>(T data,string message=null){
    var json = ApiResult<T>.Success(data);
    return Json(json);
}

在 MVC ASP.NET 中,您可以使用过滤器来捕获所有异常:

  protected override void OnException(ExceptionContext filterContext)
    {
        base.OnException(filterContext);
        filterContext.Result = Json(new ErrorApiResult("error", filterContext.Exception.Message));
    }

只是为了澄清(对于有相同问题的其他人),我想"清理"Dawood Awans 的答案,这对我的情况有所帮助,但其中有"太多"现实世界的代码,本主题不需要,并且还错过了一个关键命令,我终于在这里使用了我的解决方案:

 public class JsonExceptionAttribute:HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        if (filterContext.ExceptionHandled)
        {
            // We alread dealt with it
            return;
        }
        var jsonRet = new JsonReturn();
        filterContext.Result = 
          MyCustomJsonException(filterContext.Exception); // This is my custom method returning a JSON-String
        filterContext.ExceptionHandled = true;
    }
}

如果没有最后一个命令,此ASP/MVC仍然会引发错误