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"返回值。
我已经研究了异常处理问题,我的结论是,放置通用错误处理程序的最佳位置是global.asax.cs,Application_Error
方法。此外,禁用您可以找到的所有其他错误处理(包括 MVC 的处理),因为这可以在您不知情的情况下捕获并吞下异常。
我选择Application_Error
因为它是绝对的最终处理程序。如果这没有捕获流氓异常(没有被吞噬),那么什么都不会。例如,如果使用 MVC 错误处理,则仍然可能会遗漏一些错误 - 例如Application_BeginRequest
中的异常或缺少控制器,或 DLL 加载异常或其他任何错误。
如果不想在每个控制器操作中编写 Try Catch 语句,可以创建自己的异常处理程序。通过覆盖HandleErrorAttribute
的OnException
方法。
您现在不必将try{}catch()
添加到每个操作中,因为当发生异常时,它将调用ExceptionHandlerAttribute
的OnException
我有一个看起来像这样:
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仍然会引发错误