[英]Application_Error and ExceptionFilter
因此,我最近在ExceptionFilter處構建了該庫,用於處理除Api錯誤以外的所有錯誤。 ExceptionFilter看起來像這樣:
public class ExceptionAttribute : IExceptionFilter
{
/// <summary>
/// Handles any exception
/// </summary>
/// <param name="filterContext">The current context</param>
public void OnException(ExceptionContext filterContext)
{
// If our exception has been handled, exit the function
if (filterContext.ExceptionHandled)
return;
// If our exception is not an ApiException
if (!(filterContext.Exception is ApiException))
{
// Set our base status code
var statusCode = (int)HttpStatusCode.InternalServerError;
// If our exception is an http exception
if (filterContext.Exception is HttpException)
{
// Cast our exception as an HttpException
var exception = (HttpException)filterContext.Exception;
// Get our real status code
statusCode = exception.GetHttpCode();
}
// Set our context result
var result = CreateActionResult(filterContext, statusCode);
// Set our handled property to true
filterContext.ExceptionHandled = true;
}
}
/// <summary>
/// Creats an action result from the status code
/// </summary>
/// <param name="filterContext">The current context</param>
/// <param name="statusCode">The status code of the error</param>
/// <returns></returns>
protected virtual ActionResult CreateActionResult(ExceptionContext filterContext, int statusCode)
{
// Create our context
var context = new ControllerContext(filterContext.RequestContext, filterContext.Controller);
var statusCodeName = ((HttpStatusCode)statusCode).ToString();
// Create our route
var controller = (string)filterContext.RouteData.Values["controller"];
var action = (string)filterContext.RouteData.Values["action"];
var model = new HandleErrorInfo(filterContext.Exception, controller, action);
// Create our result
var view = SelectFirstView(context, string.Format("~/Views/Error/{0}.cshtml", statusCodeName), "~/Views/Error/Index.cshtml", statusCodeName);
var result = new ViewResult { ViewName = view, ViewData = new ViewDataDictionary<HandleErrorInfo>(model) };
// Return our result
return result;
}
/// <summary>
/// Gets the first view name that matches the supplied names
/// </summary>
/// <param name="context">The current context</param>
/// <param name="viewNames">A list of view names</param>
/// <returns></returns>
protected string SelectFirstView(ControllerContext context, params string[] viewNames)
{
return viewNames.First(view => ViewExists(context, view));
}
/// <summary>
/// Checks to see if a view exists
/// </summary>
/// <param name="context">The current context</param>
/// <param name="name">The name of the view to check</param>
/// <returns></returns>
protected bool ViewExists(ControllerContext context, string name)
{
var result = ViewEngines.Engines.FindView(context, name, null);
return result.View != null;
}
}
如您所見,如果錯誤不是 ApiException,則將用戶路由到錯誤控制器。 ApiException只是我從MVC進行API調用時發生的錯誤。 當發生這些錯誤時,我想將錯誤作為JSON返回給客戶端,以便JavaScript可以處理它。
我認為不處理該錯誤會這樣做,但相反會生成服務器錯誤(盡管其中包含JSON錯誤),如下所示:
“ /”應用程序中的服務器錯誤。
{“ message”:“ validateMove驗證失敗:\\ r \\ n該項目已發送,無法移動”}
說明:執行當前Web請求期間發生未處理的異常。 請查看堆棧跟蹤,以獲取有關錯誤及其在代碼中起源的更多信息。
異常詳細信息:SapphirePlus.Web.ApiException:{“ message”:“ validateMove驗證失敗:\\ r \\ n該項目已發送,無法移動”}
源錯誤:
第181行:if(response.StatusCode!= HttpStatusCode.OK)
第182行:拋出新的ApiException(result);
所以我的問題是,我可以獲取Application_Error方法來獲取ARE ApiException的錯誤並將錯誤作為JSON返回嗎?
所以我的問題是,我可以獲取Application_Error方法來獲取ARE ApiExceptions的錯誤並將錯誤作為JSON返回嗎?
當然:
protected void Application_Error()
{
var apiException = Server.GetLastError() as ApiException;
if (apiException != null)
{
Response.Clear();
Server.ClearError();
Response.StatusCode = 400;
Context.Response.ContentType = "application/json";
Context.Response.Write("YOUR JSON HERE");
}
}
最后,我根本不需要使用Global.asax ,我可以在ExceptionAttribute類中像下面這樣處理所有這些:
public class ExceptionAttribute : IExceptionFilter
{
/// <summary>
/// Handles any exception
/// </summary>
/// <param name="filterContext">The current context</param>
public void OnException(ExceptionContext filterContext)
{
// If our exception has been handled, exit the function
if (filterContext.ExceptionHandled)
return;
// Set our base status code
var statusCode = (int)HttpStatusCode.BadRequest;
// If our exception is an http exception
if (filterContext.Exception is HttpException)
{
// Cast our exception as an HttpException
var exception = (HttpException)filterContext.Exception;
// Get our real status code
statusCode = exception.GetHttpCode();
}
// Set our context result
var result = CreateActionResult(filterContext, statusCode);
// Set our handled property to true
filterContext.Result = result;
filterContext.ExceptionHandled = true;
}
/// <summary>
/// Creats an action result from the status code
/// </summary>
/// <param name="filterContext">The current context</param>
/// <param name="statusCode">The status code of the error</param>
/// <returns></returns>
protected virtual ActionResult CreateActionResult(ExceptionContext filterContext, int statusCode)
{
// Create our context
var context = new ControllerContext(filterContext.RequestContext, filterContext.Controller);
var statusCodeName = ((HttpStatusCode)statusCode).ToString();
// Create our route
var controller = (string)filterContext.RouteData.Values["controller"];
var action = (string)filterContext.RouteData.Values["action"];
var model = new HandleErrorInfo(filterContext.Exception, controller, action);
// Create our result
var view = SelectFirstView(context, string.Format("~/Views/Error/{0}.cshtml", statusCodeName), "~/Views/Error/Index.cshtml", statusCodeName);
var result = new ViewResult { ViewName = view, ViewData = new ViewDataDictionary<IError>(this.Factorize(model)) };
// Return our result
return result;
}
/// <summary>
/// Factorizes the HandleErrorInfo
/// </summary>
/// <param name="error"></param>
/// <returns></returns>
protected virtual IError Factorize(HandleErrorInfo error)
{
// Get the error
var model = new Error
{
Message = "There was an unhandled exception."
};
// If we have an error
if (error != null)
{
// Get our exception
var exception = error.Exception;
// If we are dealing with an ApiException
if (exception is ApiException || exception is HttpException)
{
// Get our JSON
var json = JObject.Parse(exception.Message);
var message = json["exceptionMessage"] != null ? json["exceptionMessage"] : json["message"];
// If we have a message
if (message != null)
{
// Update our model message
model.Message = message.ToString();
}
}
else
{
// Update our message
model.Message = exception.Message;
}
}
// Return our response
return model;
}
/// <summary>
/// Gets the first view name that matches the supplied names
/// </summary>
/// <param name="context">The current context</param>
/// <param name="viewNames">A list of view names</param>
/// <returns></returns>
protected string SelectFirstView(ControllerContext context, params string[] viewNames)
{
return viewNames.First(view => ViewExists(context, view));
}
/// <summary>
/// Checks to see if a view exists
/// </summary>
/// <param name="context">The current context</param>
/// <param name="name">The name of the view to check</param>
/// <returns></returns>
protected bool ViewExists(ControllerContext context, string name)
{
var result = ViewEngines.Engines.FindView(context, name, null);
return result.View != null;
}
}
這可以處理任何Mvc錯誤,對於我的Api調用,我做到了:
/// <summary>
/// Used to handle the api response
/// </summary>
/// <param name="response">The HttpResponseMessage</param>
/// <returns>Returns a string</returns>
private async Task<string> HandleResponse(HttpResponseMessage response)
{
// Read our response content
var result = await response.Content.ReadAsStringAsync();
// If there was an error, throw an HttpException
if (response.StatusCode != HttpStatusCode.OK)
throw new ApiException(result);
// Return our result if there are no errors
return result;
}
這使我可以捕獲ApiError並以不同於其他任何異常的方式處理響應。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.