- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
评论一篇文章后Exception Handling in ASP.NET Web API对于何时抛出异常与返回错误响应,我有点困惑。我还想知道当您的方法返回域特定模型而不是 HttpResponseMessage
...
所以,在这里回顾一下我的问题,然后是一些带有 case #s 的代码:
HttpResponseMessage
而不是具体的域模型,以便可以自定义消息?HttpResponseException
与 Request.CreateErrorResponse
有什么区别?客户端的输出似乎是相同的...HttpError
将响应消息“包装”在错误中(无论是抛出异常还是返回错误响应)?// CASE #1
public Customer Get(string id)
{
var customer = _customerService.GetById(id);
if (customer == null)
{
var notFoundResponse = new HttpResponseMessage(HttpStatusCode.NotFound);
throw new HttpResponseException(notFoundResponse);
}
//var response = Request.CreateResponse(HttpStatusCode.OK, customer);
//response.Content.Headers.Expires = new DateTimeOffset(DateTime.Now.AddSeconds(300));
return customer;
}
// CASE #2
public HttpResponseMessage Get(string id)
{
var customer = _customerService.GetById(id);
if (customer == null)
{
var notFoundResponse = new HttpResponseMessage(HttpStatusCode.NotFound);
throw new HttpResponseException(notFoundResponse);
}
var response = Request.CreateResponse(HttpStatusCode.OK, customer);
response.Content.Headers.Expires = new DateTimeOffset(DateTime.Now.AddSeconds(300));
return response;
}
// CASE #3
public HttpResponseMessage Get(string id)
{
var customer = _customerService.GetById(id);
if (customer == null)
{
var message = String.Format("customer with id: {0} was not found", id);
var errorResponse = Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
throw new HttpResponseException(errorResponse);
}
var response = Request.CreateResponse(HttpStatusCode.OK, customer);
response.Content.Headers.Expires = new DateTimeOffset(DateTime.Now.AddSeconds(300));
return response;
}
// CASE #4
public HttpResponseMessage Get(string id)
{
var customer = _customerService.GetById(id);
if (customer == null)
{
var message = String.Format("customer with id: {0} was not found", id);
var httpError = new HttpError(message);
return Request.CreateErrorResponse(HttpStatusCode.NotFound, httpError);
}
var response = Request.CreateResponse(HttpStatusCode.OK, customer);
response.Content.Headers.Expires = new DateTimeOffset(DateTime.Now.AddSeconds(300));
return response;
}
为了帮助进一步演示案例 #2、3、4,以下代码片段突出显示了在找不到客户时“可能发生”的几个选项...
if (customer == null)
{
// which of these 4 options is the best strategy for Web API?
// option 1 (throw)
var notFoundMessage = new HttpResponseMessage(HttpStatusCode.NotFound);
throw new HttpResponseException(notFoundMessage);
// option 2 (throw w/ HttpError)
var message = String.Format("Customer with id: {0} was not found", id);
var httpError = new HttpError(message);
var errorResponse = Request.CreateErrorResponse(HttpStatusCode.NotFound, httpError);
throw new HttpResponseException(errorResponse);
// option 3 (return)
var message = String.Format("Customer with id: {0} was not found", id);
return Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
// option 4 (return w/ HttpError)
var message = String.Format("Customer with id: {0} was not found", id);
var httpError = new HttpError(message);
return Request.CreateErrorResponse(HttpStatusCode.NotFound, httpError);
}
最佳答案
我采用的方法是仅从 api Controller 操作中抛出异常,并注册一个异常过滤器来处理异常并在操作执行上下文中设置适当的响应。
过滤器公开了一个流畅的接口(interface),该接口(interface)提供了一种在使用全局配置注册过滤器之前为特定类型的异常注册处理程序的方法。
使用此过滤器可以实现集中式异常处理,而不是将其分散到 Controller 操作中。然而,在某些情况下,如果集中处理该特定异常没有意义,我会在 Controller 操作中捕获异常并返回特定响应。
过滤器注册示例:
GlobalConfiguration.Configuration.Filters.Add(
new UnhandledExceptionFilterAttribute()
.Register<KeyNotFoundException>(HttpStatusCode.NotFound)
.Register<SecurityException>(HttpStatusCode.Forbidden)
.Register<SqlException>(
(exception, request) =>
{
var sqlException = exception as SqlException;
if (sqlException.Number > 50000)
{
var response = request.CreateResponse(HttpStatusCode.BadRequest);
response.ReasonPhrase = sqlException.Message.Replace(Environment.NewLine, String.Empty);
return response;
}
else
{
return request.CreateResponse(HttpStatusCode.InternalServerError);
}
}
)
);
UnhandledExceptionFilterAttribute 类:
using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Web.Http.Filters;
namespace Sample
{
/// <summary>
/// Represents the an attribute that provides a filter for unhandled exceptions.
/// </summary>
public class UnhandledExceptionFilterAttribute : ExceptionFilterAttribute
{
#region UnhandledExceptionFilterAttribute()
/// <summary>
/// Initializes a new instance of the <see cref="UnhandledExceptionFilterAttribute"/> class.
/// </summary>
public UnhandledExceptionFilterAttribute() : base()
{
}
#endregion
#region DefaultHandler
/// <summary>
/// Gets a delegate method that returns an <see cref="HttpResponseMessage"/>
/// that describes the supplied exception.
/// </summary>
/// <value>
/// A <see cref="Func{Exception, HttpRequestMessage, HttpResponseMessage}"/> delegate method that returns
/// an <see cref="HttpResponseMessage"/> that describes the supplied exception.
/// </value>
private static Func<Exception, HttpRequestMessage, HttpResponseMessage> DefaultHandler = (exception, request) =>
{
if(exception == null)
{
return null;
}
var response = request.CreateResponse<string>(
HttpStatusCode.InternalServerError, GetContentOf(exception)
);
response.ReasonPhrase = exception.Message.Replace(Environment.NewLine, String.Empty);
return response;
};
#endregion
#region GetContentOf
/// <summary>
/// Gets a delegate method that extracts information from the specified exception.
/// </summary>
/// <value>
/// A <see cref="Func{Exception, String}"/> delegate method that extracts information
/// from the specified exception.
/// </value>
private static Func<Exception, string> GetContentOf = (exception) =>
{
if (exception == null)
{
return String.Empty;
}
var result = new StringBuilder();
result.AppendLine(exception.Message);
result.AppendLine();
Exception innerException = exception.InnerException;
while (innerException != null)
{
result.AppendLine(innerException.Message);
result.AppendLine();
innerException = innerException.InnerException;
}
#if DEBUG
result.AppendLine(exception.StackTrace);
#endif
return result.ToString();
};
#endregion
#region Handlers
/// <summary>
/// Gets the exception handlers registered with this filter.
/// </summary>
/// <value>
/// A <see cref="ConcurrentDictionary{Type, Tuple}"/> collection that contains
/// the exception handlers registered with this filter.
/// </value>
protected ConcurrentDictionary<Type, Tuple<HttpStatusCode?, Func<Exception, HttpRequestMessage, HttpResponseMessage>>> Handlers
{
get
{
return _filterHandlers;
}
}
private readonly ConcurrentDictionary<Type, Tuple<HttpStatusCode?, Func<Exception, HttpRequestMessage, HttpResponseMessage>>> _filterHandlers = new ConcurrentDictionary<Type, Tuple<HttpStatusCode?, Func<Exception, HttpRequestMessage, HttpResponseMessage>>>();
#endregion
#region OnException(HttpActionExecutedContext actionExecutedContext)
/// <summary>
/// Raises the exception event.
/// </summary>
/// <param name="actionExecutedContext">The context for the action.</param>
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
if(actionExecutedContext == null || actionExecutedContext.Exception == null)
{
return;
}
var type = actionExecutedContext.Exception.GetType();
Tuple<HttpStatusCode?, Func<Exception, HttpRequestMessage, HttpResponseMessage>> registration = null;
if (this.Handlers.TryGetValue(type, out registration))
{
var statusCode = registration.Item1;
var handler = registration.Item2;
var response = handler(
actionExecutedContext.Exception.GetBaseException(),
actionExecutedContext.Request
);
// Use registered status code if available
if (statusCode.HasValue)
{
response.StatusCode = statusCode.Value;
}
actionExecutedContext.Response = response;
}
else
{
// If no exception handler registered for the exception type, fallback to default handler
actionExecutedContext.Response = DefaultHandler(
actionExecutedContext.Exception.GetBaseException(), actionExecutedContext.Request
);
}
}
#endregion
#region Register<TException>(HttpStatusCode statusCode)
/// <summary>
/// Registers an exception handler that returns the specified status code for exceptions of type <typeparamref name="TException"/>.
/// </summary>
/// <typeparam name="TException">The type of exception to register a handler for.</typeparam>
/// <param name="statusCode">The HTTP status code to return for exceptions of type <typeparamref name="TException"/>.</param>
/// <returns>
/// This <see cref="UnhandledExceptionFilterAttribute"/> after the exception handler has been added.
/// </returns>
public UnhandledExceptionFilterAttribute Register<TException>(HttpStatusCode statusCode)
where TException : Exception
{
var type = typeof(TException);
var item = new Tuple<HttpStatusCode?, Func<Exception, HttpRequestMessage, HttpResponseMessage>>(
statusCode, DefaultHandler
);
if (!this.Handlers.TryAdd(type, item))
{
Tuple<HttpStatusCode?, Func<Exception, HttpRequestMessage, HttpResponseMessage>> oldItem = null;
if (this.Handlers.TryRemove(type, out oldItem))
{
this.Handlers.TryAdd(type, item);
}
}
return this;
}
#endregion
#region Register<TException>(Func<Exception, HttpRequestMessage, HttpResponseMessage> handler)
/// <summary>
/// Registers the specified exception <paramref name="handler"/> for exceptions of type <typeparamref name="TException"/>.
/// </summary>
/// <typeparam name="TException">The type of exception to register the <paramref name="handler"/> for.</typeparam>
/// <param name="handler">The exception handler responsible for exceptions of type <typeparamref name="TException"/>.</param>
/// <returns>
/// This <see cref="UnhandledExceptionFilterAttribute"/> after the exception <paramref name="handler"/>
/// has been added.
/// </returns>
/// <exception cref="ArgumentNullException">The <paramref name="handler"/> is <see langword="null"/>.</exception>
public UnhandledExceptionFilterAttribute Register<TException>(Func<Exception, HttpRequestMessage, HttpResponseMessage> handler)
where TException : Exception
{
if(handler == null)
{
throw new ArgumentNullException("handler");
}
var type = typeof(TException);
var item = new Tuple<HttpStatusCode?, Func<Exception, HttpRequestMessage, HttpResponseMessage>>(
null, handler
);
if (!this.Handlers.TryAdd(type, item))
{
Tuple<HttpStatusCode?, Func<Exception, HttpRequestMessage, HttpResponseMessage>> oldItem = null;
if (this.Handlers.TryRemove(type, out oldItem))
{
this.Handlers.TryAdd(type, item);
}
}
return this;
}
#endregion
#region Unregister<TException>()
/// <summary>
/// Unregisters the exception handler for exceptions of type <typeparamref name="TException"/>.
/// </summary>
/// <typeparam name="TException">The type of exception to unregister handlers for.</typeparam>
/// <returns>
/// This <see cref="UnhandledExceptionFilterAttribute"/> after the exception handler
/// for exceptions of type <typeparamref name="TException"/> has been removed.
/// </returns>
public UnhandledExceptionFilterAttribute Unregister<TException>()
where TException : Exception
{
Tuple<HttpStatusCode?, Func<Exception, HttpRequestMessage, HttpResponseMessage>> item = null;
this.Handlers.TryRemove(typeof(TException), out item);
return this;
}
#endregion
}
}
还可以找到源代码here .
关于c# - 抛出 HttpResponseException 或返回 Request.CreateErrorResponse?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12519561/
来自 java docs 公共(public) FileWriter(String fileName) 抛出 IOException 抛出: IOException - 如果指定的文件存在但它是目录而
我使用以下代码将我的 .net 客户端(基于 CQL)连接到 3 节点 Cassandra 集群。我以 30 条记录/秒的速度(从 RabbitMQ)获取数据,并且它们顺利地存储在 cassandra
如果在读取文件时缺少字段,我应该捕获 NoSuchElementException。如果缺少一个字段,我只需要跳到文件的下一行。我的问题是,我在哪里实现我的 try/catch 代码来做到这一点?这是
我正在尝试使用 ASP.NET MVC 实现 OpeinID 登录。我正在尝试按照 http://blog.nerdbank.net/2008/04/add-openid-login-support-
学习使用 Java 进行 xml 解析,并且正在编写一个测试程序来尝试各种东西。所有测试 System.out.println() 都是我在控制台中所期望的,除了 childElement 返回 [n
我正在尝试使用 SwingUtilities 创建 JFrame Thread tt = new Thread(new Runnable() { public void run
关闭。这个问题是not reproducible or was caused by typos .它目前不接受答案。 这个问题是由于错别字或无法再重现的问题引起的。虽然类似的问题可能是on-topi
我写了这段代码: MethodInfo method2 = typeof(IntPtr).GetMethod( "op_Explicit", Bind
我开始学习 Java,并且正在根据书本做一些练习。在执行此操作时,我遇到了以下错误:线程“main”java.util.InputMismatchException 中出现异常。我正在编写一个简单的程
我有一个文本文件,其中前两行是整数 m 和 n,然后有 m 行,每行都有 n 管道分隔值。我编写了一个程序,读取文件并使用文件中的值创建 m*n 数组,它工作了无数次,然后突然,使用相同的代码,使用相
所以我尝试使用在另一个类中生成的 bean 以在主应用程序中使用 package com.simon.spring.basics.properties; import org.spri
我还没有完成这个应用程序,但我希望在我的手机上看到它的样子。但是,它会强制关闭并引发 InstantiationException。 logcat 异常: 09-19 20:13:47.987: D/
我想从 UIViewController 加载一个基于 SwiftUI 的 View ,该 View 读取包本地的 json。仅 swiftUI 项目中的代码和绑定(bind)工作正常,当我利用 UI
'java.net.SocketTimeoutException:连接超时' 循环一段时间后我收到此错误。为什么我会收到 SocketTimeoutException?我该如何修复这个错误? @Ove
当有 null 值时抛出 ArgumentNullException() 是个好主意吗? This thread 没有提到在 null 上抛出的最明显的异常。 谢谢 最佳答案 ArgumentNull
我得到这个异常: NullReferenceException Object reference not set to an instance of an object at Namespace
所以其中一个方法的描述如下: public BasicLinkedList addToFront(T data) This operation is invalid for a sorted list
我正在使用 Intellij Idea,当我去生成 JavaDocs(通过工具 -> 生成 JavaDoc)时,我抛出了一个 IllegealArgumentException,没有关于发生了什么问题
我正在学习 C++ 中的互斥锁,但以下代码(摘自 N. Josuttis 的“C++ 标准库”)有问题。 我不明白为什么它会阻塞/抛出除非我在主线程中添加this_thread::sleep_for(
我正在试验 JavaFX 标签和组,通过鼠标拖动将它们移动到屏幕上。新节点从一些线程添加到动画组。但是,有时我会突然看到以下异常 - 我假设,当某些节点重叠时。但是不知道是什么问题……因为不涉及我的代
我是一名优秀的程序员,十分优秀!