Web API和MVCexception处理

我们目前正在将我们的Web表单系统重新开发为Web API和MVC(这对我们来说是新技术)到目前为止,一切似乎都没问题,但我们正在努力将Web API应用程序中的错误发送回MVC应用程序。 我们意识到我们需要捕获任何exception,并将这些exception转换为HTTP响应

Web API Product控制器如下所示:

public HttpResponseMessage GetProducts() { BAProduct c = new BAProduct(); var d = c.GetProducts(); if (d == null) return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "This is a custom error message"); else return Request.CreateResponse(HttpStatusCode.OK, d); } 

MVC应用程序将通过以下代码调用Web API: –

 public T Get() using (HttpClient client = new HttpClient()) { client.BaseAddress = new Uri(Config.API_BaseSite); client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = client.GetAsync("api/myapplicaton/products").Result; response.EnsureSuccessStatusCode(); T res = response.Content.ReadAsAsync().Result; return (T)res; } } 

我们想要实现的是当从MVC应用程序中的Web API收到HTTP错误时,用户被重定向到自定义错误页面,或者在当前视图中显示自定义错误消息(取决于错误)。 我们遇到的问题是: –

  1. 如何访问我们发回的自定义错误消息? (从示例代码中这将是“这是一个自定义错误消息”,我们已经通过res中的每个属性并且看不到此消息)

  2. 根据状态代码,我们如何捕获并将用户重定向到各个错误页面,即404页面,500页面,并显示已发回的自定义响应消息。 我们一直沿着global.asax路线走下去

     protected void Application_Error(object sender, EventArgs e) { Exception exception = Server.GetLastError(); Response.Clear(); HttpException httpException = exception as HttpException; 

但是我们的httpExecption总是为NULL

我们搜索过等等,到目前为止,找不到合适的东西,希望有人可以指出我们正确的方向。

你的httpException实例为null的原因是因为response.EnsureSuccessStatusCode(); 方法不会抛出HttpException ,这是您尝试将其强制转换为的。 它抛出了一个不同的HttpRequestException ,但没有简单的方法来获取更多细节(例如状态代码)。

作为调用此方法的替代方法,您可以测试IsSuccessStatusCode布尔属性并IsSuccessStatusCode抛出HttpException

 public T Get() { using (HttpClient client = new HttpClient()) { client.BaseAddress = new Uri(Config.API_BaseSite); client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = client.GetAsync("api/myapplicaton/products").Result; if (!response.IsSuccessStatusCode) { string responseBody = response.Content.ReadAsStringAync().Result; throw new HttpException((int)response.StatusCode, responseBody); } T res = response.Content.ReadAsAsync().Result; return (T)res; } } 

现在可以在Application_Error捕获此HttpException ,并根据状态代码继续处理:

 protected void Application_Error() { var exception = Server.GetLastError(); var httpException = exception as HttpException; Response.Clear(); Server.ClearError(); var routeData = new RouteData(); routeData.Values["controller"] = "Errors"; routeData.Values["action"] = "Http500"; routeData.Values["exception"] = exception; Response.StatusCode = 500; Response.TrySkipIisCustomErrors = true; if (httpException != null) { Response.StatusCode = httpException.GetHttpCode(); switch (Response.StatusCode) { case 403: routeData.Values["action"] = "Http403"; break; case 404: routeData.Values["action"] = "Http404"; break; // TODO: Add other cases if you want to handle // different status codes from your Web API } } IController errorsController = new ErrorsController(); var rc = new RequestContext(new HttpContextWrapper(Context), routeData); errorsController.Execute(rc); } 

在这个例子中,我假设你有一个ErrorsController与各自的动作(Http500,Http403,Http404,…)。 将根据状态代码调用相应的操作,您可以返回不同的视图。


更新:

您可能希望捕获HTTP请求的其他工件(例如原因短语),以便在错误页面中显示它。 在这种情况下,您可以编写自己的exception,其中包含您需要的信息:

 public class ApiException : Exception { public HttpStatusCode StatusCode { get; set; } public string Reason { get; set; } public string ResponseBody { get; set; } } 

你可以抛出:

 if (!response.IsSuccessStatusCode) { throw new ApiException { StatusCode = response.StatusCode, Reason = response.ReasonPhrase, ResponseBody = response.Content.ReadAsStringAync().Result, }; } 

然后在Application_Error使用此自定义exception。

这里有解决上述问题的优秀post

它主要有两个主要步骤 –

步骤1:反序列化HTTP错误结果中的响应内容,例如

 var httpErrorObject = response.Content.ReadAsStringAsync().Result; // Create an anonymous object to use as the template for deserialization: var anonymousErrorObject = new { message = "", ModelState = new Dictionary() }; // Deserialize: var deserializedErrorObject = JsonConvert.DeserializeAnonymousType(httpErrorObject, anonymousErrorObject); 

步骤2:在ModelState Dictionaries Client-Side中添加错误

 foreach (var error in apiEx.Errors) { ModelState.AddModelError("", error); } 

使用deserializedErrorObject在apiEx.Errors中添加字符串错误消息。

请参阅链接