C# MVC3和WebApi错误处理
我正在编辑一个使用MVC3的旧项目。 它有一个Global.asax文件,可处理如下错误:C# MVC3和WebApi错误处理,c#,asp.net-mvc,asp.net-mvc-3,asp.net-web-api,C#,Asp.net Mvc,Asp.net Mvc 3,Asp.net Web Api,我正在编辑一个使用MVC3的旧项目。 它有一个Global.asax文件,可处理如下错误: protected void Application_Error(object sender, EventArgs e) { var currentController = " "; var currentAction = " "; var currentRouteData = RouteTable.Routes.GetRouteData(new HttpContextWrappe
protected void Application_Error(object sender, EventArgs e)
{
var currentController = " ";
var currentAction = " ";
var currentRouteData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(Context));
if (currentRouteData != null)
{
if (currentRouteData.Values["controller"] != null && !String.IsNullOrEmpty(currentRouteData.Values["controller"].ToString()))
currentController = currentRouteData.Values["controller"].ToString();
if (currentRouteData.Values["action"] != null && !String.IsNullOrEmpty(currentRouteData.Values["action"].ToString()))
currentAction = currentRouteData.Values["action"].ToString();
}
var ex = Server.GetLastError();
var controller = new ErrorController();
var routeData = new RouteData();
var action = "Index";
var code = (ex is HttpException) ? (ex as HttpException).GetHttpCode() : 500;
switch (code)
{
case 400:
action = "BadRequest";
break;
case 401:
action = "Unauthorized";
break;
case 403:
action = "Forbidden";
break;
case 404:
action = "NotFound";
break;
case 500:
action = "InternalServerError";
break;
default:
action = "Index";
break;
}
Server.ClearError();
Response.Clear();
Response.StatusCode = code;
Response.TrySkipIisCustomErrors = true;
routeData.Values["controller"] = "Error";
routeData.Values["action"] = action;
controller.ViewData.Model = new HandleErrorInfo(ex, currentController, currentAction);
((IController)controller).Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
/// <summary>
/// Used to make a Get request to a specified url
/// </summary>
/// <param name="url">The target url</param>
/// <returns>Returns a string</returns>
public async Task<string> MakeApiCall(string url)
{
return await MakeApiCall(url, HttpMethod.GET, null);
}
/// <summary>
/// Used to make a Post request to a specified url
/// </summary>
/// <param name="url">The target url</param>
/// <param name="method">The Http method</param>
/// <param name="data">The object to send to the api</param>
/// <returns>Returns a string</returns>
public async Task<string> MakeApiCall(string url, HttpMethod method, object data)
{
// Create our local variables
var client = new HttpClient();
var user = Session["AccessToken"];
var authenticating = user == null;
// If we are not authenticating, set our auth token
if (!authenticating)
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Session["AccessToken"].ToString());
// Check to see what HTTP method is being used
switch (method)
{
case HttpMethod.POST:
// If we are POSTing, then perform a post request
return await PostRequest(client, url, data, authenticating);
default:
// If we are GETing, then perform a get request
return await GetRequest(client, url);
}
}
#region Helper methods
/// <summary>
/// Posts data to a specifed url
/// </summary>
/// <param name="client">The HttpClient used to make the api call</param>
/// <param name="url">The target url</param>
/// <param name="data">The object to send to the api</param>
/// <param name="authenticating">Used to set the content type when authenticating</param>
/// <returns>Returns a string</returns>
private async Task<string> PostRequest(HttpClient client, string url, object data, bool authenticating)
{
// If the data is a string, then do a normal post, otherwise post as json
var response = (data is string) ? await client.PostAsync(this.apiUrl + url, new StringContent(data.ToString())) : await client.PostAsJsonAsync(this.apiUrl + url, data);
// If we are authenticating, set the content type header
if (authenticating == true)
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
// Handle our response
return await HandleResponse(response);
}
/// <summary>
/// Gets data from a specifed url
/// </summary>
/// <param name="client">The HttpClient used to make the api call</param>
/// <param name="url">The target url</param>
/// <returns>Returns a string</returns>
private async Task<string> GetRequest(HttpClient client, string url)
{
// Perform the get request
var response = await client.GetAsync(this.apiUrl + url);
// Handle our response
return await HandleResponse(response);
}
/// <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 HttpException((int)response.StatusCode, result);
// Return our result if there are no errors
return result;
}
#endregion
/// <summary>
/// Custom Api Exception
/// </summary>
public class ApiException : Exception
{
/// <summary>
/// Default constructor
/// </summary>
public ApiException()
{
}
/// <summary>
/// Constructor with message
/// </summary>
/// <param name="message">The error message as a string</param>
public ApiException(string message)
: base(message)
{
}
/// <summary>
/// Constructor with message and inner exception
/// </summary>
/// <param name="message">The error message as a string</param>
/// <param name="inner">The inner exception</param>
public ApiException(string message, Exception inner)
: base(message, inner)
{
}
}
/// <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;
}
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;
}
}
当我的MVC项目中出现错误时,这可以正常工作。
还有一个基类调用外部API,如下所示:
protected void Application_Error(object sender, EventArgs e)
{
var currentController = " ";
var currentAction = " ";
var currentRouteData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(Context));
if (currentRouteData != null)
{
if (currentRouteData.Values["controller"] != null && !String.IsNullOrEmpty(currentRouteData.Values["controller"].ToString()))
currentController = currentRouteData.Values["controller"].ToString();
if (currentRouteData.Values["action"] != null && !String.IsNullOrEmpty(currentRouteData.Values["action"].ToString()))
currentAction = currentRouteData.Values["action"].ToString();
}
var ex = Server.GetLastError();
var controller = new ErrorController();
var routeData = new RouteData();
var action = "Index";
var code = (ex is HttpException) ? (ex as HttpException).GetHttpCode() : 500;
switch (code)
{
case 400:
action = "BadRequest";
break;
case 401:
action = "Unauthorized";
break;
case 403:
action = "Forbidden";
break;
case 404:
action = "NotFound";
break;
case 500:
action = "InternalServerError";
break;
default:
action = "Index";
break;
}
Server.ClearError();
Response.Clear();
Response.StatusCode = code;
Response.TrySkipIisCustomErrors = true;
routeData.Values["controller"] = "Error";
routeData.Values["action"] = action;
controller.ViewData.Model = new HandleErrorInfo(ex, currentController, currentAction);
((IController)controller).Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
/// <summary>
/// Used to make a Get request to a specified url
/// </summary>
/// <param name="url">The target url</param>
/// <returns>Returns a string</returns>
public async Task<string> MakeApiCall(string url)
{
return await MakeApiCall(url, HttpMethod.GET, null);
}
/// <summary>
/// Used to make a Post request to a specified url
/// </summary>
/// <param name="url">The target url</param>
/// <param name="method">The Http method</param>
/// <param name="data">The object to send to the api</param>
/// <returns>Returns a string</returns>
public async Task<string> MakeApiCall(string url, HttpMethod method, object data)
{
// Create our local variables
var client = new HttpClient();
var user = Session["AccessToken"];
var authenticating = user == null;
// If we are not authenticating, set our auth token
if (!authenticating)
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Session["AccessToken"].ToString());
// Check to see what HTTP method is being used
switch (method)
{
case HttpMethod.POST:
// If we are POSTing, then perform a post request
return await PostRequest(client, url, data, authenticating);
default:
// If we are GETing, then perform a get request
return await GetRequest(client, url);
}
}
#region Helper methods
/// <summary>
/// Posts data to a specifed url
/// </summary>
/// <param name="client">The HttpClient used to make the api call</param>
/// <param name="url">The target url</param>
/// <param name="data">The object to send to the api</param>
/// <param name="authenticating">Used to set the content type when authenticating</param>
/// <returns>Returns a string</returns>
private async Task<string> PostRequest(HttpClient client, string url, object data, bool authenticating)
{
// If the data is a string, then do a normal post, otherwise post as json
var response = (data is string) ? await client.PostAsync(this.apiUrl + url, new StringContent(data.ToString())) : await client.PostAsJsonAsync(this.apiUrl + url, data);
// If we are authenticating, set the content type header
if (authenticating == true)
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
// Handle our response
return await HandleResponse(response);
}
/// <summary>
/// Gets data from a specifed url
/// </summary>
/// <param name="client">The HttpClient used to make the api call</param>
/// <param name="url">The target url</param>
/// <returns>Returns a string</returns>
private async Task<string> GetRequest(HttpClient client, string url)
{
// Perform the get request
var response = await client.GetAsync(this.apiUrl + url);
// Handle our response
return await HandleResponse(response);
}
/// <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 HttpException((int)response.StatusCode, result);
// Return our result if there are no errors
return result;
}
#endregion
/// <summary>
/// Custom Api Exception
/// </summary>
public class ApiException : Exception
{
/// <summary>
/// Default constructor
/// </summary>
public ApiException()
{
}
/// <summary>
/// Constructor with message
/// </summary>
/// <param name="message">The error message as a string</param>
public ApiException(string message)
: base(message)
{
}
/// <summary>
/// Constructor with message and inner exception
/// </summary>
/// <param name="message">The error message as a string</param>
/// <param name="inner">The inner exception</param>
public ApiException(string message, Exception inner)
: base(message, inner)
{
}
}
/// <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;
}
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;
}
}
这反过来又被Global.asax中的应用程序错误方法捕获。问题是,由于这是一个API调用,控制器无法重定向到ErrorController
所以我的问题是:
protected void Application_Error(object sender, EventArgs e)
{
var currentController = " ";
var currentAction = " ";
var currentRouteData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(Context));
if (currentRouteData != null)
{
if (currentRouteData.Values["controller"] != null && !String.IsNullOrEmpty(currentRouteData.Values["controller"].ToString()))
currentController = currentRouteData.Values["controller"].ToString();
if (currentRouteData.Values["action"] != null && !String.IsNullOrEmpty(currentRouteData.Values["action"].ToString()))
currentAction = currentRouteData.Values["action"].ToString();
}
var ex = Server.GetLastError();
var controller = new ErrorController();
var routeData = new RouteData();
var action = "Index";
var code = (ex is HttpException) ? (ex as HttpException).GetHttpCode() : 500;
switch (code)
{
case 400:
action = "BadRequest";
break;
case 401:
action = "Unauthorized";
break;
case 403:
action = "Forbidden";
break;
case 404:
action = "NotFound";
break;
case 500:
action = "InternalServerError";
break;
default:
action = "Index";
break;
}
Server.ClearError();
Response.Clear();
Response.StatusCode = code;
Response.TrySkipIisCustomErrors = true;
routeData.Values["controller"] = "Error";
routeData.Values["action"] = action;
controller.ViewData.Model = new HandleErrorInfo(ex, currentController, currentAction);
((IController)controller).Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
/// <summary>
/// Used to make a Get request to a specified url
/// </summary>
/// <param name="url">The target url</param>
/// <returns>Returns a string</returns>
public async Task<string> MakeApiCall(string url)
{
return await MakeApiCall(url, HttpMethod.GET, null);
}
/// <summary>
/// Used to make a Post request to a specified url
/// </summary>
/// <param name="url">The target url</param>
/// <param name="method">The Http method</param>
/// <param name="data">The object to send to the api</param>
/// <returns>Returns a string</returns>
public async Task<string> MakeApiCall(string url, HttpMethod method, object data)
{
// Create our local variables
var client = new HttpClient();
var user = Session["AccessToken"];
var authenticating = user == null;
// If we are not authenticating, set our auth token
if (!authenticating)
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Session["AccessToken"].ToString());
// Check to see what HTTP method is being used
switch (method)
{
case HttpMethod.POST:
// If we are POSTing, then perform a post request
return await PostRequest(client, url, data, authenticating);
default:
// If we are GETing, then perform a get request
return await GetRequest(client, url);
}
}
#region Helper methods
/// <summary>
/// Posts data to a specifed url
/// </summary>
/// <param name="client">The HttpClient used to make the api call</param>
/// <param name="url">The target url</param>
/// <param name="data">The object to send to the api</param>
/// <param name="authenticating">Used to set the content type when authenticating</param>
/// <returns>Returns a string</returns>
private async Task<string> PostRequest(HttpClient client, string url, object data, bool authenticating)
{
// If the data is a string, then do a normal post, otherwise post as json
var response = (data is string) ? await client.PostAsync(this.apiUrl + url, new StringContent(data.ToString())) : await client.PostAsJsonAsync(this.apiUrl + url, data);
// If we are authenticating, set the content type header
if (authenticating == true)
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
// Handle our response
return await HandleResponse(response);
}
/// <summary>
/// Gets data from a specifed url
/// </summary>
/// <param name="client">The HttpClient used to make the api call</param>
/// <param name="url">The target url</param>
/// <returns>Returns a string</returns>
private async Task<string> GetRequest(HttpClient client, string url)
{
// Perform the get request
var response = await client.GetAsync(this.apiUrl + url);
// Handle our response
return await HandleResponse(response);
}
/// <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 HttpException((int)response.StatusCode, result);
// Return our result if there are no errors
return result;
}
#endregion
/// <summary>
/// Custom Api Exception
/// </summary>
public class ApiException : Exception
{
/// <summary>
/// Default constructor
/// </summary>
public ApiException()
{
}
/// <summary>
/// Constructor with message
/// </summary>
/// <param name="message">The error message as a string</param>
public ApiException(string message)
: base(message)
{
}
/// <summary>
/// Constructor with message and inner exception
/// </summary>
/// <param name="message">The error message as a string</param>
/// <param name="inner">The inner exception</param>
public ApiException(string message, Exception inner)
: base(message, inner)
{
}
}
/// <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;
}
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;
}
}
//
///自定义Api异常
///
公共类异常:异常
{
///
///默认构造函数
///
公共例外()
{
}
///
///带消息的构造函数
///
///以字符串形式显示错误消息
公共API异常(字符串消息)
:base(消息)
{
}
///
///具有消息和内部异常的构造函数
///
///以字符串形式显示错误消息
///内部例外
公共ApiException(字符串消息,内部异常)
:base(消息,内部)
{
}
}
然后,我在基本控制器中更新了我的HandlerResponse方法,如下所示:
protected void Application_Error(object sender, EventArgs e)
{
var currentController = " ";
var currentAction = " ";
var currentRouteData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(Context));
if (currentRouteData != null)
{
if (currentRouteData.Values["controller"] != null && !String.IsNullOrEmpty(currentRouteData.Values["controller"].ToString()))
currentController = currentRouteData.Values["controller"].ToString();
if (currentRouteData.Values["action"] != null && !String.IsNullOrEmpty(currentRouteData.Values["action"].ToString()))
currentAction = currentRouteData.Values["action"].ToString();
}
var ex = Server.GetLastError();
var controller = new ErrorController();
var routeData = new RouteData();
var action = "Index";
var code = (ex is HttpException) ? (ex as HttpException).GetHttpCode() : 500;
switch (code)
{
case 400:
action = "BadRequest";
break;
case 401:
action = "Unauthorized";
break;
case 403:
action = "Forbidden";
break;
case 404:
action = "NotFound";
break;
case 500:
action = "InternalServerError";
break;
default:
action = "Index";
break;
}
Server.ClearError();
Response.Clear();
Response.StatusCode = code;
Response.TrySkipIisCustomErrors = true;
routeData.Values["controller"] = "Error";
routeData.Values["action"] = action;
controller.ViewData.Model = new HandleErrorInfo(ex, currentController, currentAction);
((IController)controller).Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
/// <summary>
/// Used to make a Get request to a specified url
/// </summary>
/// <param name="url">The target url</param>
/// <returns>Returns a string</returns>
public async Task<string> MakeApiCall(string url)
{
return await MakeApiCall(url, HttpMethod.GET, null);
}
/// <summary>
/// Used to make a Post request to a specified url
/// </summary>
/// <param name="url">The target url</param>
/// <param name="method">The Http method</param>
/// <param name="data">The object to send to the api</param>
/// <returns>Returns a string</returns>
public async Task<string> MakeApiCall(string url, HttpMethod method, object data)
{
// Create our local variables
var client = new HttpClient();
var user = Session["AccessToken"];
var authenticating = user == null;
// If we are not authenticating, set our auth token
if (!authenticating)
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Session["AccessToken"].ToString());
// Check to see what HTTP method is being used
switch (method)
{
case HttpMethod.POST:
// If we are POSTing, then perform a post request
return await PostRequest(client, url, data, authenticating);
default:
// If we are GETing, then perform a get request
return await GetRequest(client, url);
}
}
#region Helper methods
/// <summary>
/// Posts data to a specifed url
/// </summary>
/// <param name="client">The HttpClient used to make the api call</param>
/// <param name="url">The target url</param>
/// <param name="data">The object to send to the api</param>
/// <param name="authenticating">Used to set the content type when authenticating</param>
/// <returns>Returns a string</returns>
private async Task<string> PostRequest(HttpClient client, string url, object data, bool authenticating)
{
// If the data is a string, then do a normal post, otherwise post as json
var response = (data is string) ? await client.PostAsync(this.apiUrl + url, new StringContent(data.ToString())) : await client.PostAsJsonAsync(this.apiUrl + url, data);
// If we are authenticating, set the content type header
if (authenticating == true)
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
// Handle our response
return await HandleResponse(response);
}
/// <summary>
/// Gets data from a specifed url
/// </summary>
/// <param name="client">The HttpClient used to make the api call</param>
/// <param name="url">The target url</param>
/// <returns>Returns a string</returns>
private async Task<string> GetRequest(HttpClient client, string url)
{
// Perform the get request
var response = await client.GetAsync(this.apiUrl + url);
// Handle our response
return await HandleResponse(response);
}
/// <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 HttpException((int)response.StatusCode, result);
// Return our result if there are no errors
return result;
}
#endregion
/// <summary>
/// Custom Api Exception
/// </summary>
public class ApiException : Exception
{
/// <summary>
/// Default constructor
/// </summary>
public ApiException()
{
}
/// <summary>
/// Constructor with message
/// </summary>
/// <param name="message">The error message as a string</param>
public ApiException(string message)
: base(message)
{
}
/// <summary>
/// Constructor with message and inner exception
/// </summary>
/// <param name="message">The error message as a string</param>
/// <param name="inner">The inner exception</param>
public ApiException(string message, Exception inner)
: base(message, inner)
{
}
}
/// <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;
}
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;
}
}
//
///用于处理api响应
///
///HttpResponseMessage
///返回一个字符串
专用异步任务句柄响应(HttpResponseMessage响应)
{
//阅读我们的回复内容
var result=await response.Content.ReadAsStringAsync();
//如果出现错误,则抛出HttpException
if(response.StatusCode!=HttpStatusCode.OK)
抛出新异常(结果);
//如果没有错误,请返回我们的结果
返回结果;
}
然后我创建了一个过滤器,并将其添加到过滤器配置中,如下所示:
protected void Application_Error(object sender, EventArgs e)
{
var currentController = " ";
var currentAction = " ";
var currentRouteData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(Context));
if (currentRouteData != null)
{
if (currentRouteData.Values["controller"] != null && !String.IsNullOrEmpty(currentRouteData.Values["controller"].ToString()))
currentController = currentRouteData.Values["controller"].ToString();
if (currentRouteData.Values["action"] != null && !String.IsNullOrEmpty(currentRouteData.Values["action"].ToString()))
currentAction = currentRouteData.Values["action"].ToString();
}
var ex = Server.GetLastError();
var controller = new ErrorController();
var routeData = new RouteData();
var action = "Index";
var code = (ex is HttpException) ? (ex as HttpException).GetHttpCode() : 500;
switch (code)
{
case 400:
action = "BadRequest";
break;
case 401:
action = "Unauthorized";
break;
case 403:
action = "Forbidden";
break;
case 404:
action = "NotFound";
break;
case 500:
action = "InternalServerError";
break;
default:
action = "Index";
break;
}
Server.ClearError();
Response.Clear();
Response.StatusCode = code;
Response.TrySkipIisCustomErrors = true;
routeData.Values["controller"] = "Error";
routeData.Values["action"] = action;
controller.ViewData.Model = new HandleErrorInfo(ex, currentController, currentAction);
((IController)controller).Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
/// <summary>
/// Used to make a Get request to a specified url
/// </summary>
/// <param name="url">The target url</param>
/// <returns>Returns a string</returns>
public async Task<string> MakeApiCall(string url)
{
return await MakeApiCall(url, HttpMethod.GET, null);
}
/// <summary>
/// Used to make a Post request to a specified url
/// </summary>
/// <param name="url">The target url</param>
/// <param name="method">The Http method</param>
/// <param name="data">The object to send to the api</param>
/// <returns>Returns a string</returns>
public async Task<string> MakeApiCall(string url, HttpMethod method, object data)
{
// Create our local variables
var client = new HttpClient();
var user = Session["AccessToken"];
var authenticating = user == null;
// If we are not authenticating, set our auth token
if (!authenticating)
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Session["AccessToken"].ToString());
// Check to see what HTTP method is being used
switch (method)
{
case HttpMethod.POST:
// If we are POSTing, then perform a post request
return await PostRequest(client, url, data, authenticating);
default:
// If we are GETing, then perform a get request
return await GetRequest(client, url);
}
}
#region Helper methods
/// <summary>
/// Posts data to a specifed url
/// </summary>
/// <param name="client">The HttpClient used to make the api call</param>
/// <param name="url">The target url</param>
/// <param name="data">The object to send to the api</param>
/// <param name="authenticating">Used to set the content type when authenticating</param>
/// <returns>Returns a string</returns>
private async Task<string> PostRequest(HttpClient client, string url, object data, bool authenticating)
{
// If the data is a string, then do a normal post, otherwise post as json
var response = (data is string) ? await client.PostAsync(this.apiUrl + url, new StringContent(data.ToString())) : await client.PostAsJsonAsync(this.apiUrl + url, data);
// If we are authenticating, set the content type header
if (authenticating == true)
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
// Handle our response
return await HandleResponse(response);
}
/// <summary>
/// Gets data from a specifed url
/// </summary>
/// <param name="client">The HttpClient used to make the api call</param>
/// <param name="url">The target url</param>
/// <returns>Returns a string</returns>
private async Task<string> GetRequest(HttpClient client, string url)
{
// Perform the get request
var response = await client.GetAsync(this.apiUrl + url);
// Handle our response
return await HandleResponse(response);
}
/// <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 HttpException((int)response.StatusCode, result);
// Return our result if there are no errors
return result;
}
#endregion
/// <summary>
/// Custom Api Exception
/// </summary>
public class ApiException : Exception
{
/// <summary>
/// Default constructor
/// </summary>
public ApiException()
{
}
/// <summary>
/// Constructor with message
/// </summary>
/// <param name="message">The error message as a string</param>
public ApiException(string message)
: base(message)
{
}
/// <summary>
/// Constructor with message and inner exception
/// </summary>
/// <param name="message">The error message as a string</param>
/// <param name="inner">The inner exception</param>
public ApiException(string message, Exception inner)
: base(message, inner)
{
}
}
/// <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;
}
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;
}
}
公共类例外属性:IEExceptionFilter
{
///
///处理任何异常
///
///当前环境
公共无效OneException(例外上下文筛选器上下文)
{
//如果我们的异常已被处理,请退出该函数
if(filterContext.ExceptionHandled)
返回;
//如果我们的例外不是一个例外
如果(!(filterContext.Exception为ApiException))
{
//设置我们的基本状态代码
var statusCode=(int)HttpStatusCode.InternalServerError;
//如果我们的异常是http异常
if(filterContext.Exception为HttpException)
{
//将我们的异常强制转换为HttpException
var exception=(HttpException)filterContext.exception;
//获取我们的真实状态代码
statusCode=exception.GetHttpCode();
}
//设置上下文结果
var result=CreateActionResult(filterContext,statusCode);
//将我们处理的属性设置为true
filterContext.ExceptionHandled=true;
}
}
///
///根据状态代码创建操作结果
///
///当前环境
///错误的状态代码
///
受保护的虚拟ActionResult CreateActionResult(上下文筛选器上下文、int状态代码除外)
{
//创造我们的环境
var context=newcontrollercontext(filterContext.RequestContext,filterContext.Controller);
var statusCodeName=((HttpStatusCode)statusCode).ToString();
//创建我们的路线
变量控制器=(字符串)filterContext.RouteData.Values[“controller”];
var action=(字符串)filterContext.RouteData.Values[“action”];
var模型=新HandleErrorInfo(filterContext.Exception,controller,action);
//创造我们的结果
var view=SelectFirstView(context,string.Format(“~/Views/Error/{0}.cshtml”,statusCodeName),“~/Views/Error/Index.cshtml”,statusCodeName);
var result=newviewresult{ViewName=view,ViewData=newviewdatadictionary(model)};
//返回我们的结果
返回结果;
}
///
///获取与提供的名称匹配的第一个视图名称
///
///当前环境
///视图名称的列表
///
受保护的字符串SelectFirstView(ControllerContext上下文,参数字符串[]视图名称)
{
返回viewNames.First(view=>ViewExists(context,view));
}
///
///检查视图是否存在
///
///当前环境
///要检查的视图的名称
///
受保护的布尔视图存在(ControllerContext上下文、字符串名称)
{
var result=ViewEngines.Engines.FindView(上下文、名称、null);
返回结果。视图!=null;
}
}
最后,我从Global.asax中的应用程序错误方法中删除了逻辑,希望这能起作用。但事实并非如此。当出现ApiException时,我仍然会得到一个返回的文档
有人能帮我吗
我是否可以忽略Global.asax错误处理,只返回JSON,这样我的JavaScript就可以决定如何处理错误了
由于Global.asax
是ASP.NET管道的一部分,因此没有本机方法可以忽略它。您可能会求助于一些黑客,但是如果您使用MVC和WebApi框架来解决这个问题,而不是依赖过时的ASP.NET行为,那就更好了
有更好的方法吗
在这两种情况下都可以使用异常过滤器